提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言:
在这里我们要先了解sizeof和strlen的作用
再通过他们来理解数组名,取地址数组名,和指向数组里面元素的指针,和取地址数组元素等的意义
一、sizeof和strlen的用法
sizeof是操作符,strlen是包含再string.h里面的库函数
- sizeof()用于计算类型所占空间大小,他不会计算()内的值,仅仅是计算所占空间大小而已。举个例子:
int main() { short s = 5; printf("%d\n", sizeof(s = 1 + 1)); printf("%d\n", s); return 0; }
这个计算出来第一个是2,第二个是5,一个表达式有两个属性,一个叫值属性,一个叫类型属性,而sizeof计算的就是类型属性。
-
int main() { int arr[3] = {0}; printf("%d\n", sizeof(arr[4])); return 0; }
知道是计算类型属性的话,即使数组越界了也是能够正常作用的。这里计算出来结果就是4,一个int型。
2. size_t strlen(const char* str);这是strlen的定义,由定义可以知道,我们传入一个指针,得到一个整形,它的计算该整数是从该指针指向的元素开始开始,一直++,直到遇到'\0'停止. 例子:
int main()
{
char a[] = { 'a','b','c' };
char b[] = { 'a','b','c','\0' };
printf("%d\n", strlen(a));
printf("%d\n", strlen(b));
return 0;
}
二、了解指针
1.利用整形数组来了解指针
代码如下(示例):
int a[4] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(a[1]));
注:除了sizeof(数组名)和&数组名,取出的是整个数组地址外,其余的都是首元素
(以下答案以vs2022,x86环境参考)
一张图知道符号指代什么:虽然地址值一样,但是意义却不一样,接下来我们来找出这些意义的不同
1.第一个,sizeof计算数组类型的大小,整个数组大小为4*4=16
2.第二个,a是指向数组首元素的指针,+0之后还是代表指向首元素的指针,注意区分a,它此时不是数组名了,只是一个指针,所以这里计算的是地址的大小了,结果为4
3.第三个,a是指向数组首元素的指针,解引用后就是数组首元素,因为首元素类型是int型,这里计算的是元素类型大小,所以这里计算出来的是4
4.第四个,a是指向数组首元素的指针,a的类型是int*,所以+1向后跳过一个int型,a+1就变成了指向数组第二个元素的指针,这里计算的是指针的大小,所以这里计算出来的是4
5.第五个,a[1]就是数组第二个元素,这里计算的是元素类型大小,所以这里计算出来的是4
vs截图:
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
先理解a和&a有什么区别呢?
1. 先看各自地址:
可以看到地址是一样的,都是取的首元素的地址。
2.再看访问权限:
可以看到,a + 1跳过一个int型,而&a + 1跳过4*4个int型,即跳过了一个数组,由此可以知道&a取的是一个数组的地址,它的类型就是int (*)[4],一个数组指针。
知道了这两点后再看题:
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
1.第一个,sizeof计算的是一个数组指针的大小,所以结果为一个指针的大小,即4
2.第二个,&a取的是一个数组的指针int (*)[4],所以解引用后就变成了int [4],即一个数组类型,所以结果是4*4=16
3.第三个,&a + 1即向后跳一个数组,这时候它指向为:
它的类型仍然是int (*)[4],所以结果仍然是一个指针大小,即4
4.第四个,a[0]代表第一个元素,&它即为指向第一个元素的指针,结果为4
5.第五个,指向第一个元素的指针加1,所以指向第二个元素,如图:
它的类型是一个整形指针,所以结果为4
2.利用字符数组来了解指针
代码如下(示例):
char arr[6] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
strlen只管接收地址,然后从该地址出发寻找'\0'
一张图理解指代什么:
1.第一个,arr代表首元素地址,所以从首元素地址出发,寻找,结果为随机值
2.第二个,arr + 0也是代表首元素地址,所以结果也是随机值
3.第三个,arr代表首元素地址,解引用就找到了首元素'a',实参传入的会是a的ASCII值,97,即0x00000061,强制将其转换成地址并且访问,然后出错:
4.第四个,与第三个一样,arr[1]代表第二个元素,出错
5.第五个,&arr代表取该数组的地址,类型为char (*)[6],但是该地址的数据和首元素地址一样,所以传参时发生类型转换,数据不转换,所以它的意思是,从首元素出发寻找,结果为随机值
6.第六个,&arr代表数组地址,加一后跳过一个数组,如下图:
所以,它的结果为随机值-6
7.第七个,arr[0]代表第一个元素,&它即为指向第一个元素的指针,加一后指向第二个元素,如下图:
所以,它的结果为随机值-1
vs截图:
3.利用字符指针来理解指针
代码如下(示例):
char* p = "abcdef";
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(&p));
先以一张图来了解整个题目符号都指代什么:
1.第一个,p是一个指向常量字符串首字符’a'的指针,从a出发寻找'\0',所以结果为6
2.第二个,p + 1的意思就会是字符指针向后移动一个单位,这时指向了”b’,从b出发寻找'\0’,所以结果是5
3.第三个,*p即寻找到了字符'a',这时是会发生访问冲突
4.第四个,p[0]也代表了首元素,发生访问冲突
5.第五个,p是指向字符'a'的指针,&p就会表示指向指针p的指针,这种指向一级指针的指针叫做二级指针,它的模式从上图也可以看到,它的类型是也还是指针,&p地址传入的话会从指向指针p存储的数据的第一个单元格开始访问,直到访问到'\0',这时候答案就会是随机值了
6.第六个,,&p就会表示指向指针p的指针,它的类型是也还是指针,访问权限也就是一个指针的大小,所以如上图,从p指针外的第一个单元格开始访问,它的值也是随机值
(注意:第5和6的随机值是没关联的,因为可能在p的四个单元格内就出现了'\0')
7.第七个,p[0]代表字符'a',&它的地址,就代表取字符'a'的地址,这时候加一就指向了字符'b',代表指向字符'b'的指针,从b开始访问,所以结果为5
8.第八个,p是一个指向常量字符串首字符’a'的指针,类型是指针,所以结果为4
9.第九个,p是一个指针,&p是指向p指针的指针,它的类型其实还是一个指针,所以结果为4
三,总结
1. 我们看指针时,要理解它的意义,我们要注意它指向哪里,它的访问权限时多少。
存储的地址可能相同,但是访问权限不同的话,它的意义也就不同了。
2. 利用sizeof时,siezof是计算类型的大小;它不会计算里面的表达式。