指针和数组练习
文章目录
1. sizeof 巩固
1.1概念
sizeof是C语言的一种单目操作符,如C语言的其他操作符++、–等。它并不是函数。
sizeof操作符以字节形式给出了其操作数的存储大小。
操作数可以是一个表达式或括在括号内的类型名。
操作数的存储大小由操作数的类型决定。
1.2 sizeof的结果(以下结果都是在vs2019获取)
该类型保证能容纳实现所建立的最大对象的字节大小.
1.2.1 ANSI C正式规定字符类型为1字节。
sizeof(char) = 1;
sizeof(unsigned char) = 1;
sizeof(signed char) = 1;
1.2.2 其他类型在ANSI C中没有具体规定,大小取决于编译器及操作系统。
sizeof(int) = 4;
sizeof(unsigned int) = 4;
sizeof(short int) = 2;
sizeof(unsigned short) = 2;
sizeof(long int) = 4;
sizeof(unsigned long) = 4;
sizeof(float) = 4;
sizeof(double) = 8;
sizeof(long double) = 16;
1.2.3当操作数是函数中的数组形参或函数类型的形参:
sizeof给出其指针的大小,32位系统中指针值为4,64为系统中指针值为8。
2. strlen巩固
2.1 概念
strlen是C语言标准函数库中的标准函数,其功能是:计算字符串的长度,strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符==’\0’==为止,然后返回计数器值(长度不包含’\0’)。
3. sizeof和strlen区别
-
sizeof是取字节运算符(关键字),strlen是函数。
-
sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以’\0’结尾的。
-
数组做sizeof的参数不退化,传递给strlen就退化为指针了。
4. 练习1
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));//结果 16
printf("%d\n",sizeof(a+0));//结果 4
printf("%d\n",sizeof(*a));//结果 4
printf("%d\n",sizeof(a+1));//结果 4
printf("%d\n",sizeof(a[1]));//结果 4
printf("%d\n",sizeof(&a));//结果 4
printf("%d\n",sizeof(*&a));//结果 16
printf("%d\n",sizeof(&a+1));//结果 4
printf("%d\n",sizeof(&a[0]));//结果 4
printf("%d\n",sizeof(&a[0]+1));//结果 4
分析:
- 对于 sizeof(a) 传入的是数组名,相当于传入整个数组,数组大小为4,且为int型,每个元素占四个字节,所以总共占用4*4=16;
- 对于sizeof(a+0) 传入的不仅仅是数组名,而是数组名+0,所以数组名相当于首元素地址,首元素地址+0还是首元素地址,所以相当于求1的地址所占字节,32位系统指针大小均为4字节,所以结果为4;
- 对于sizeof(*a)传入的是*a,a是数组首元素地址,*a就是首元素,所以相当于求数组第一个元素1所占字节数,1为int型,大小为4字节;
- 对于sizeof(a+1)传入的是a+1,a是数组首元素地址,a+1就是数组第二个元素地址,所以相当于求数组第二个元素2地址所占大小,大小为4字节;
- 对于sizeof(a[1]),相当于求数组第二个元素2所占字节数,2为int型,大小为4字节;
- 对于sizeof(&a),&a取出的是整个数组的地址,地址32位系统均为4字节;
- 对于sizeof(*&a),a是数组首元素地址,&a取出的是整个数组的地址,*&a相当于又将地址解引用,还是数组,最终相当于sizeof(a),同分析1,16字节。
- sizeof(&a+1),&a取出的是整个数组的地址,&a+1相当于跳过这个数组后紧接的那个地址,地址为4字节;
- sizeof(&a[0]),&a[0]取出的是数组第一个元素的地址,地址为4字节;
- sizeof(&a[0]+1),&a[0]取出的是数组第一个元素的地址,&a[0]+1相当于取出第二个元素地址,地址为4字节。
**tips:**数组名表示首元素地址
但当sizeof()中传入数组名时,计算的是数组总大小,单位是字节,
当==&数组名==,数组名表示整个数组,取出的是整个数组的地址,除此以外,所有数组名都是取出首元素地址。
5. 练习2
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr)); 6
printf("%d\n", sizeof(arr+0)); 4
printf("%d\n", sizeof(*arr)); 1
printf("%d\n", sizeof(arr[1]));1
printf("%d\n", sizeof(&arr));4
printf("%d\n", sizeof(&arr+1));4
printf("%d\n", sizeof(&arr[0]+1));4
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));随机值
分析:
- 对于 sizeof(arr),传入的是数组名,相当于计算整个数组大小,数组大小为6,类型为char,6*1=6字节;
- 对于sizeof(arr+0),传入的不仅仅是数组名,而是数组名+0,所以数组名相当于首元素地址,首元素地址+0还是首元素地址,所以相当于求**‘a’的地址**所占字节,32位系统指针大小均为4字节,所以结果为4;
- 对于sizeof(arr),传入的是*a,a是数组首元素地址,*a就是首元素,所以相当于求数组第一个元素*‘a’所占字节数,‘a’**为char型,大小为1字节;
- 对于sizeof(arr[1]),相当于求sizeof(‘b’),char型,大小1字节;
- 对于sizeof(&arr),相当于求数组地址大小,32位系统下,指针大小4字节;
- 同练习1分析,指针大小4字节;
- 同练习1分析,指针大小4字节;
- 由于strlen检测到‘\0’才会停止,数组中并没有‘\0’,所以将会依次查找数组后邻接的地址,直到找到‘\0’停止,所以随机值;
- 首元素地址+0还是首元素地址,同上,随机值;
- *a为数组第一个元素‘a’,strlen函数应传入地址,实际求‘a’所对应ASCII码值97为开始地址的字符串长度,但是97并不属于数组地址,将会报错。
- 同上,报错;
- 同8,随机值;
- 同上,随机值;比12的随机值少6(因为&arr+1跳过了整个数组);
- 同上,随机值,比12的随机值少1(因为&arr[0]+1位第二个元素开始计算)。
6. 练习3
char arr[] = "abcdef";
printf("%d\n", sizeof(arr)); 7
printf("%d\n", sizeof(arr+0)); 4
printf("%d\n", sizeof(*arr)); 1
printf("%d\n", sizeof(arr[1])); 1
printf("%d\n", sizeof(&arr)); 4
printf("%d\n", sizeof(&arr+1)); 4
printf("%d\n", sizeof(&arr[0]+1)); 4
printf("%d\n", strlen(arr)); 6
printf("%d\n", strlen(arr+0));6
printf("%d\n", strlen(*arr));错误
printf("%d\n", strlen(arr[1]));错误
printf("%d\n", strlen(&arr));6
printf("%d\n", strlen(&arr+1))随机;
printf("%d\n", strlen(&arr[0]+1));5
分析:
- 对于 sizeof(arr),传入的是数组名,相当于计算整个数组大小,数组大小为7(字符串后还有’\0‘),类型为char,6*1=6字节;
- 对于sizeof(arr+0),传入的不仅仅是数组名,而是数组名+0,所以数组名相当于首元素地址,首元素地址+0还是首元素地址,所以相当于求**‘a’的地址**所占字节,32位系统指针大小均为4字节,所以结果为4;
- 对于sizeof(arr),传入的是*a,a是数组首元素地址,*a就是首元素,所以相当于求数组第一个元素*‘a’所占字节数,‘a’**为char型,大小为1字节;
- 对于sizeof(arr[1]),相当于求sizeof(‘b’),char型,大小1字节;
- 对于sizeof(&arr),相当于求数组地址大小,32位系统下,指针大小4字节;
- 同练习1分析,指针大小4字节;
- 同练习1分析,指针大小4字节;
- arr为首元素地址,由于strlen检测到‘\0’才会停止,数组中并最后一位为‘\0’,所以6字节;
- 首元素地址+0还是首元素地址,同上,6字节;
- *a为数组第一个元素‘a’,strlen函数应传入地址,实际求‘a’所对应ASCII码值97为开始地址的字符串长度,但是97并不属于数组地址,将会报错;
- 同上,报错;
- &arr为首元素地址,同分析8大小6字节;
- &arr+1,为跳过该数组,即为从’\0‘后第一个位置开始查找’\0‘,所以值随机;
- &arr为首元素地址,&arr+1为第一个元素地址,同分析8,大小5字节;
7. 练习4
char *p = "abcdef";
printf("%d\n", sizeof(p));4
printf("%d\n", sizeof(p+1));4
printf("%d\n", sizeof(*p));1
printf("%d\n", sizeof(p[0]));1
printf("%d\n", sizeof(&p));4
printf("%d\n", sizeof(&p+1));4
printf("%d\n", sizeof(&p[0]+1));4
printf("%d\n", strlen(p));6
printf("%d\n", strlen(p+1));5
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));5
分析:
-
对于 sizeof§,p是指向第一个元素a的指针,32位系统下均为4字节;
-
sizeof(p+1),p是首元素地址,p+1是第二个元素地址,4字节;
-
sizeof(*p),p为首元素地址,*p为第一个元素a,a为char类型,1字节;
-
sizeof(p[0]),p[0]为第一个元素a,a为char类型,1字节;
-
sizeof(&p),&p为得到p的地址,4字节;
-
sizeof(&p+1),&p为得到p的地址,&p+1为得到p的邻接位置的元素地址,4字节;
-
sizeof(&p[0]+1),&p[0]为第一个元素a的地址,&p[0]+1为第二个元素b的地址,4字节;
-
strlen§,p为首元素地址,由于strlen检测到‘\0’才会停止,数组中并最后一位为‘\0’,所以6字节;
-
strlen(p+1),p+1为第二个元素地址,由于strlen检测到‘\0’才会停止,数组中并最后一位为‘\0’,所以5字节;
-
*p为数组第一个元素‘a’,strlen函数应传入地址,实际求‘a’所对应ASCII码值97为开始地址的字符串长度,但是97并不属于数组地址,将会报错;
-
同上报错;
-
strlen(&p),由于p存放的是常量“abcdef”首元素‘’a“的地址,与原字符串地址没有关系,如下图所示,所以实际所求为p所在地址为起始地址的字符串长度,所以为随机值;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EFS6209e-1621435628040)(C:\Users\14275\AppData\Roaming\Typora\typora-user-images\image-20210519091802120.png)]
- strlen(&p+1),&p+1为p所在位置的邻接位置地址如上图所示,结果同上,随机值;
- strlen(&p[0]+1),&p[0]为第一个元素a的地址,&p[0]+1为第二个元素b的地址,所以长度为6-1=5;
8. 练习5
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));48
printf("%d\n", sizeof(a[0][0]));4
printf("%d\n", sizeof(a[0]));16
printf("%d\n", sizeof(a[0] + 1));4
printf("%d\n", sizeof(*(a[0] + 1)));4
printf("%d\n", sizeof(a + 1));4
printf("%d\n", sizeof(*(a + 1)));16
printf("%d\n", sizeof(&a[0] + 1));4
printf("%d\n", sizeof(*(&a[0] + 1)));16
printf("%d\n", sizeof(*a));16
printf("%d\n", sizeof(a[3]));16
分析:
- sizeof(a),a为数组名,所以求的是整个数组大小,总共有3*4=12个int元素,12*4=48字节
- sizeof(a[0][0]),a[0][0]为第一元素的值,第一个元素为int型,4字节;
- sizeof(a[0]),a[0]为第一行元素首地址,所以求的是第一行数组的大小,4*4=16字节;
- sizeof(a[0] + 1),由于a[0]没有单独在括号中,所以其为第一行第一个元素地址,所以a[0] + 1为第一行第二个元素地址,地址32位系统均为4字节;
- sizeof(*(a[0] + 1)),a[0] + 1为第一行第二个元素地址,*(a[0] + 1)为第二个元素值,int型为4字节;
- sizeof(a + 1),由于a没有单独在括号中,其相当于第一行首元素的地址,a+1相当于第二行首元素的地址,地址4字节;
- sizeof(*(a + 1)),对第二行数组解引用,得到第二行数组,大小为4*4=16字节;
- sizeof(&a[0] + 1),&a[0]取出第一行地址,&a[0] + 1取出第二行地址,地址为4字节;
- sizeof(*(&a[0] + 1)),第二行数组大小,4*4=16字节;
- sizeof(*a),第一行地址解引用得到第一行数组,16字节;
- sizeof(a[3]),第四行数组,16字节(虽然越界,但是sizeof并没有访问其内存,只是计算大小)。
的地址,地址4字节;
7. sizeof((a + 1)),对第二行数组解引用,得到第二行数组,大小为4*4=16字节;
8. sizeof(&a[0] + 1),&a[0]取出第一行地址,&a[0] + 1取出第二行地址,地址为4字节;
9. sizeof(*(&a[0] + 1)),第二行数组大小,4*4=16字节;
10. sizeof(*a),第一行地址解引用得到第一行数组,16字节;
11. sizeof(a[3]),第四行数组,16字节(虽然越界,但是sizeof并没有访问其内存,只是计算大小)。