一维数组:
int a[10];
int *p=&a[0] p=&a[0] *p=a[0]
p+1->&a[0]+1 //指针加1在数值上表示加了1个指向类型的长度sizeof(int)
p+1->&a[0]+1->&a[1] 以此类推
p+2->&a[0]+2->&a[2]
.......................................
p+i->&a[0]+i->&a[i]
在一个数组中,如果定义了一个指针保存a[0]的地址,则有式子 p+i->&a[0]+i->&a[i]
*(p+i)->*(&a[0]+i)->*(&a[i])->a[i]
1、在以上条件的基础上,假如要把100的值赋给a[0],请问有几种方法?
a[0]=100 <-> *(&a[0])=100 <-> *p=100 <-> *a=100 <-> *(p+0)=100 <-> p[0]=100
2、假如int a[10],int *p=&a[2],请问p[2]表示:
p->&a[2] --> p[2] <-> *(&p[2]) <-> *(&p[0]+2) <-> *(p+2) <-> *(&a[2]+2) <-> *(&a[4])
a[2] <-> *(&a[2]) <-> *(&a[0]+2) <-> *(a+2) <-> a[2]
int a[10] int *p=a <-> int *p=&a[0] ==> p=a ==> p=&a[0]
数组名可以代表数组的首元素地址 a <-> &a[0]
sizeof(a):求整个数组的大小
typeof(a):求这个数组的类型
typeof(p) <-> typeof(&a[0]) <-> typeof(a[0])* <-> int * ===> typeof(&x) <-> typeof(x)*
p=a:都是保存了a[0]的地址
a+1:&a[0]+1==>&a[1] //这个时候把数组名当做指针来用
*(a+1):*(&a[0]+1)==>*(&a[1])==>a[1] //这个时候把数组名当做指针来用
int a[10]={1,2,3,4,5,6,7,8,9,10}
int a[10] <==> int[10] a <==> typeof(a) ==> int [10]
a:&a[0]
a+1:&a[0]+1 <==> &a[1]
&a+1:a是数组,&a表示的是数组的指针,指针做加减,要观察指针的类型===>&a typeof(&a) ==> typeof(a)* ==> (int [10])* ==> 表示每次指针加减都是在10个int类型的基础上进行! &a+1 ==> 加10个int大小的字节
&a[0]+1:typeof(&a[0]) ==> typeof(a[0])* ==> int * ==>指针每次加减是在一个int字节的基础上
注意:
a:&a[0] 数组首元素地址
&a[0]:取数组的第一个元素的地址
&a:取整个数组的地址,这是一个指向数组的地址
typeof(&a) <==> typeof(a)* <==> (int[10])*:指针每次加减是在10个int大小字节的基础上进行
typeof(&a[0]) <==> typeof(a[0])* <==> int*:指针每次加减都是在1个int大小字节的基础上进行
二维数组:
int b[2][3]={1,2,3,4,5,6}
二维数组本质是一个一维数组:int b[2][3] ==>(int[3]) b[2]
b:数组名做数组首元素地址 ==> &b[0]
&b:这里把b看做整个数组
&b+1:指针做加减看类型==> typeof(&b) ==> typeof(b)* ==> (int[2][3])* :指针加减都是在一整个二维数组大小的字节数的基础上
b+1:&b[0]+1 指针加减看类型:typeof(&b[0]) ==> typeof(b[0])* ==>int[3]* 指针每次加减在一个3个int大小的字节的基础上 b+1 ==> &b[0]+1 ==> &b[1]
&b[0]+1:typeof(&b[0]) ==> typeof(b[0])* ==> (int[3])* &b[0]+1==>&b[1]
int a[5]={1,2,3,4,5}
int *ptr=(int*)(&a+1)
分析:typeof(&a)==>typeof(a)*==>(int[5])*:指针每次加减都是加减整个数组5个int字节大小 强制类型转换成(int*),变成指针每次加减一个int字节大小
*(a+1):*(&a[0]+1) 指针加减看类型,typeof(&a[0])=typeof(a[0])*=int*:指针每次加减一个int字节大小,所以*(&a[0]+1)=*(&a[1])=a[1]
*(ptr-1):ptr本来是(&a+1),数组的首地址往后移动了5个int字节大小,强制转换成int*类型,指针每次加减1个int字节大小,ptr-1往前移动一个int字节,所以是a[4]=5;
在上面二维数组的基础上,要定义一个指针变量p,保存数组的第一个数值b[0][0]的地址,该如何定义呢?
typeof(b[0][0])=int* ==> 所以可以这样定义p ===>int *p=&b[0][0]
二维数组名b代表的意思有:&b[0],如果要用指针p保存这个地址的话,应该怎么去写呢?
typeof(b[0]) == (int[3])* ===> 所以可以这样定义p的类型 ===> (int[3])* p=&b[0]=b ===> 因为类型和数字不能连在一起===>int (*p) [3]=&b[0]=b ==>这样也叫数组指针
数组指针:
数组指针归根结底是指针,指向一个数组,用来保存数组的地址;
像上面部分写的那样,int (*p) [3]=&b[0]=b,
指针数组:
指针数组是一个数组,数组里面的每个元素是指针;
int* p[3]:定义一个数组p,里面有3个int*,3个int类型的指针;
区别:
数组指针:int (*p)[3]
指针数组:int *p[3]
注意:要避免访问未初始化的指针!
定义一个二维数组int a[3][4] ==> (int [4] a[3]);
表达式 | 类型 | 含义 |
a+i | int [4] | 第i行的首地址&a[i] |
*(a+i)+j | int* | 第i行第j列的元素的地址 |
*(*(a+i)+j) | int | 第i行第j列的元素 |
表达式 | 表达式的值 | 表达式的含义 |
a | 表示数组名 sizeof(a)、typeof(a)代表整个数组 &a代表一个指针 | 数组的首元素地址&a[0] |
a[0] | 表示数组名 sizeof(a[0])、typeof(a[0])代表整个数组 &a[0]代表一个指针 | 表示数组第一行第一个元素的地址 |
a[0][0] | 表示数组元素 | 表示数组第一行第一列的元素 |
a+1 | a是指针,&a[0]+1=&a[1] | 数组第二行的首元素地址 |
&a+1 | typeof(&a) ---> int [3][4] *,&a+1:指向下一个数组a类型元素的首地址(加了一整个数组a的大小) | |
a[1]+2 | &a[1][0]+2 | &a[1][2] |
*(a+1)+2 | *(&a[0]+1)+2==>*(&a[1])+2===>a[1]+2===> &a[1][0]+2 ==>&a[1][2] | |
*(a[1]+2) | *(&a[1][0]+2)==>*(&a[1][2])==> a[1][2] | |
*(*(a+1)+2) | *(*(&a[0]+1)+2)==>*(a[1]+2)==>*(&a[1][0]+2)==>a[1][2] |
- 第二个:*(a+i)+j,可以表示为*(&a[0]+i)+j,可以表示为*(&a[i])+j ==>a[i]+j,a[i]这里是一个一维数组,在这里当指针使用,a[i]+j ==> &a[i][0]+j ==> &a[i][j],所以typeof(&a[i][j])==>typeof(a[i][j])*==>int *
- 第八个: typeof(&a) ---> int [3][4] *
&a+1:指向下一个数组a类型元素的首地址(加了一整个数组a的大小)
指针变量作为函数的参数:
一定要记住:C语言中的函数参数传递永远是一个值传递;
把一个变量的地址传递给了函数,并且可以通过这个地址间接访问原来那个变量,不受作用于的限制;
数组做函数的参数
一维数组作为函数的参数:
int a[10];
f(int p[],int n)
{
//p[i] ===> a[i]
} f(a,10)
也可以这样写:
f_2(int *x,int n)
{
//x[i] ===> a[i]
}
f_2(a,10);
二维数组作为数组的参数: int a[3][4];
typeof(a);//a是一个二维数组名,也是一个指针,是第一行的首地址
===>typeof(&a[0]) ===> int [4] *
===> int (*x)[4]
fun(int (*x)[4],int n)
字符串和指针
字符在计算机中是以ASCLL码值保存的,C语言中字符串是通过char*(字符型指针)来实现的
C语言的字符串,是用""(双引号)引出来的一串字符进行表示的,并且字符串后默认加了一个'\0'(终止符,ASCII码为0),这个就是字符串结束的标志
"" 字符串,字符串常量
typeof("12345") ===> const char * 常量指针
char *p = "abcde";
*p = 'A';//ERROR,p指向的字符串是只读的,
p[2] = 'A';//ERROR
*(p+2) = 'A';//ERROR
表示字符串的方法有两个:
- char s[]="hello"; ==========> 表示字符数组
- char *p="hello"; ==========>指针实现的字符串表达
指针常量和常量指针
常量指针:指针可以指向别的地方,但它指向的内容不允许被改变(字符串)
指针常量:指针的指向不允许被改变,但是可以改变上面的值(数组名)
用法和区别(待补充)
数组长度
字符串大小,数组元素的个数,一个字符数组,必须到它本身的\0才结束计算,而且,本身自带的\0也算数组长度的一个计算在内,数组内容里面出现‘\0’算一个字符;用sizeof去表示;
字符串长度
从传入的字符串首地址开始往下找,每有一个不是'\0'的字符的时候,长度+1,当碰到'\0'的时候,结束计算,并且'\0'不会计算在其中;用strlen去表示;
这是我在学C语言中,通过老师讲解和询问同学对自己的学习的一个总结,文中有不对或说法不准确的地方,恳请各位大佬指正!
本人的评论区欢迎大家讨论技术性的问题!