(本文参考《C和指针》第六章 第八章)
《C和指针》第六章主要讲指针的概念和简单用法,对于初学者要仔细看(燃不清地址和值得),对于有c语言基础比较简单;
第八章加入了数组,数组和指针,二维数组和指针,相比第六章有进阶,本文重点分析书中几个题。
一、第六章指针:概念
1.指针是啥?简单说就是地址
2.间接访问操作符:*
什么是间接访问?间接访问又或者说解引用指针就是:通过一个指针访问它所指向的地址的过程。
3.未初始化的指针:野指针
4.空指针:NULL,对NULL指针间接访问将引发错误并终止程序。
5.分析如下表达式:
int a;
* & a = 25;
答案:给变量a赋值为25;首先&操作符取a的地址,*从操作符对该地址解引用(间接访问);
和 a = 25;的区别:功能相同,但前者产生的目标代码明显更大更复杂,所以也没人这样写。
6.指针常量:
如下表达式:*100 = 25;(已知100为变量的地址)
该表达式错误!因为*(解引用操作符)只能对指针类型表达式起作用,如果想要完成该功能(将25存在地址为100的内存区域),需要这样写:*(int*)100 = 25;使用强转。
7.指针的指针:
如下表达式:
int a= 1234;
int* b = &a;
int** c = &b;
8.指针运算:(注意void* 指针)
(1)指针+指针:不合法
(2)指针+-数字:合法,表示单元格的移动
(3)指针-指针:表示两指针中间单元格的数目
(4)int a = 10; void * p = &a;
思考:p++是否合法??*p = 20;//解引用 给a赋值20 是否合法??
答案是不合法的。,为什么指针可以做减法运算和自减了,就是因为一个前提:知道指针的类型,int*的指针,那么指针减减就是指针见一的单元格,单元格是4个字节,char*的指针减减,就是一个单元格一个字节。
所以void * ,无类型,做指针减法运算就不知道一个单元格是几个字节了,也就无法运算,所以不合法。
同理,不知道指针的数据类型,也就不知道解引用的数据类型,所以就不能解引用。
二、第八章:指针和数组
一、一维数组:
1.数组名的几个情况
1.在定义数组arr的同一个函数中,sizeof(arr)表示整个数组的大小
2.在定义数组arr的同一个函数中,&arr+1,加整个数组的大小
3.其它情况,arr表示首元素的地址
书中有这样一句话:“在C中,几乎所有的表达式中,数组名的值是一个指针常量,也就是数组第1个元素的地址。”
但有两个除外:如下:
(1)sizeof()求数组名大小,数组名未退化为指针,所有求得大小是整个数组的大小
int main()
{
char arr[] = "hello world";
char* p = arr;
cout<<strlen(arr)<<endl;//11 strlen求有效长度
cout<<sizeof(arr)<<endl; //12 sizeof(数组名)求这个结构大小,当然算'\0'了
cout<<strlen(p)<<endl; //11等同于strlen(arr)
cout<<sizeof(p)<<endl; //4指针都是4
return 0;
}
(2)&arr+1 :表示取数组整个的大小,再+1表示到数组最后一个元素的后一个地址。
如图可见,第一个arr[0]表示第一个元素,&arr[0] == arr == &arr;
arr+1:指针+1表示+1个单元格,即int*类型的指针加1个单元格,+4字节
但是&arr+1的意义就完全不一样了,&arr已经是作为一个整体了,再+1,就是相当于加这一个整体的单元格,也就是指向第5个单元格,虽然第5个单元格我们并没有使用(其值为0xcccccccc)。
再分析下题:
int arr[]= {1,2,3,4};
int* p1 = (int*)(&arr+1);
int* p2 = (int*)((int)arr + 1);
int* p3 = (int*)((int)&arr + 1);
printf("0x%x 0x%x 0x%x\n",p1[-1],*p2,*p3);
2.数组名下标 和 指针+整数
int arr[10];
int* p = arr;
则:arr[2] == *(arr+2) == *(p+2)
3.字符数组的初始化:
char message[] = { 'a' , 'b','c' , 'd' ,0};
char message[] ="abcd"; //二者相同
二、二维数组:
1.下标:如图分析
2.指针数组与数组指针
(1)指针数组:它是数组,存的东西是指针。int* p[4]; 没啥好说的,比较简单
(2)数组指针:它是指针,指向的是一个数组:int (*p)[10] :指向整形数组的指针,该数组有10个元素
例如:
int mat[3][10];
int (*p)[10] = mat;// p指向mat的第一行(指向拥有10个int元素的数组的指针),p+整数,则该整数要根据10个int值得长度调整,然后执行+法,也就说p在mat中一行一行的移动