指针和数组练习

指针和数组练习

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区别

  1. sizeof是取字节运算符(关键字),strlen是函数。

  2. sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以’\0’结尾的。

  3. 数组做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

分析:

  1. 对于 sizeof(a) 传入的是数组名,相当于传入整个数组,数组大小为4,且为int型,每个元素占四个字节,所以总共占用4*4=16;
  2. 对于sizeof(a+0) 传入的不仅仅是数组名,而是数组名+0,所以数组名相当于首元素地址,首元素地址+0还是首元素地址,所以相当于求1地址所占字节,32位系统指针大小均为4字节,所以结果为4;
  3. 对于sizeof(*a)传入的是*a,a是数组首元素地址,*a就是首元素,所以相当于求数组第一个元素1所占字节数,1为int型,大小为4字节;
  4. 对于sizeof(a+1)传入的是a+1,a是数组首元素地址,a+1就是数组第二个元素地址,所以相当于求数组第二个元素2地址所占大小,大小为4字节;
  5. 对于sizeof(a[1]),相当于求数组第二个元素2所占字节数,2为int型,大小为4字节;
  6. 对于sizeof(&a),&a取出的是整个数组的地址,地址32位系统均为4字节;
  7. 对于sizeof(*&a),a是数组首元素地址,&a取出的是整个数组的地址,*&a相当于又将地址解引用,还是数组,最终相当于sizeof(a),同分析1,16字节。
  8. sizeof(&a+1),&a取出的是整个数组的地址,&a+1相当于跳过这个数组后紧接的那个地址,地址为4字节;
  9. sizeof(&a[0]),&a[0]取出的是数组第一个元素的地址,地址为4字节;
  10. 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));随机值

分析:

  1. 对于 sizeof(arr),传入的是数组名,相当于计算整个数组大小,数组大小为6,类型为char,6*1=6字节;
  2. 对于sizeof(arr+0),传入的不仅仅是数组名,而是数组名+0,所以数组名相当于首元素地址,首元素地址+0还是首元素地址,所以相当于求**‘a’地址**所占字节,32位系统指针大小均为4字节,所以结果为4;
  3. 对于sizeof(arr),传入的是*a,a是数组首元素地址,*a就是首元素,所以相当于求数组第一个元素*‘a’所占字节数,‘a’**为char型,大小为1字节;
  4. 对于sizeof(arr[1]),相当于求sizeof(‘b’),char型,大小1字节;
  5. 对于sizeof(&arr),相当于求数组地址大小,32位系统下,指针大小4字节;
  6. 同练习1分析,指针大小4字节;
  7. 同练习1分析,指针大小4字节;
  8. 由于strlen检测到‘\0’才会停止,数组中并没有‘\0’,所以将会依次查找数组后邻接的地址,直到找到‘\0’停止,所以随机值;
  9. 首元素地址+0还是首元素地址,同上,随机值;
  10. *a为数组第一个元素‘a’,strlen函数应传入地址,实际求‘a’所对应ASCII码值97为开始地址的字符串长度,但是97并不属于数组地址,将会报错。
  11. 同上,报错;
  12. 同8,随机值;
  13. 同上,随机值;比12的随机值少6(因为&arr+1跳过了整个数组);
  14. 同上,随机值,比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

分析:

  1. 对于 sizeof(arr),传入的是数组名,相当于计算整个数组大小,数组大小为7(字符串后还有’\0‘),类型为char,6*1=6字节;
  2. 对于sizeof(arr+0),传入的不仅仅是数组名,而是数组名+0,所以数组名相当于首元素地址,首元素地址+0还是首元素地址,所以相当于求**‘a’地址**所占字节,32位系统指针大小均为4字节,所以结果为4;
  3. 对于sizeof(arr),传入的是*a,a是数组首元素地址,*a就是首元素,所以相当于求数组第一个元素*‘a’所占字节数,‘a’**为char型,大小为1字节;
  4. 对于sizeof(arr[1]),相当于求sizeof(‘b’),char型,大小1字节;
  5. 对于sizeof(&arr),相当于求数组地址大小,32位系统下,指针大小4字节;
  6. 同练习1分析,指针大小4字节;
  7. 同练习1分析,指针大小4字节;
  8. arr为首元素地址,由于strlen检测到‘\0’才会停止,数组中并最后一位为‘\0’,所以6字节;
  9. 首元素地址+0还是首元素地址,同上,6字节;
  10. *a为数组第一个元素‘a’,strlen函数应传入地址,实际求‘a’所对应ASCII码值97为开始地址的字符串长度,但是97并不属于数组地址,将会报错;
  11. 同上,报错;
  12. &arr为首元素地址,同分析8大小6字节;
  13. &arr+1,为跳过该数组,即为从’\0‘后第一个位置开始查找’\0‘,所以值随机;
  14. &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

分析:

  1. 对于 sizeof§,p是指向第一个元素a的指针,32位系统下均为4字节;

  2. sizeof(p+1),p是首元素地址,p+1是第二个元素地址,4字节;

  3. sizeof(*p),p为首元素地址,*p为第一个元素a,a为char类型,1字节;

  4. sizeof(p[0]),p[0]为第一个元素a,a为char类型,1字节;

  5. sizeof(&p),&p为得到p的地址,4字节;

  6. sizeof(&p+1),&p为得到p的地址,&p+1为得到p的邻接位置的元素地址,4字节;

  7. sizeof(&p[0]+1),&p[0]为第一个元素a的地址,&p[0]+1为第二个元素b的地址,4字节;

  8. strlen§,p为首元素地址,由于strlen检测到‘\0’才会停止,数组中并最后一位为‘\0’,所以6字节;

  9. strlen(p+1),p+1为第二个元素地址,由于strlen检测到‘\0’才会停止,数组中并最后一位为‘\0’,所以5字节;

  10. *p为数组第一个元素‘a’,strlen函数应传入地址,实际求‘a’所对应ASCII码值97为开始地址的字符串长度,但是97并不属于数组地址,将会报错;

  11. 同上报错;

  12. strlen(&p),由于p存放的是常量“abcdef”首元素‘’a“的地址,与原字符串地址没有关系,如下图所示,所以实际所求为p所在地址为起始地址的字符串长度,所以为随机值;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EFS6209e-1621435628040)(C:\Users\14275\AppData\Roaming\Typora\typora-user-images\image-20210519091802120.png)]

    1. strlen(&p+1),&p+1为p所在位置的邻接位置地址如上图所示,结果同上,随机值;
    2. 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

分析:

  1. sizeof(a),a为数组名,所以求的是整个数组大小,总共有3*4=12个int元素,12*4=48字节
  2. sizeof(a[0][0]),a[0][0]为第一元素的值,第一个元素为int型,4字节;
  3. sizeof(a[0]),a[0]为第一行元素首地址,所以求的是第一行数组的大小,4*4=16字节;
  4. sizeof(a[0] + 1),由于a[0]没有单独在括号中,所以其为第一行第一个元素地址,所以a[0] + 1为第一行第二个元素地址,地址32位系统均为4字节;
  5. sizeof(*(a[0] + 1)),a[0] + 1为第一行第二个元素地址,*(a[0] + 1)为第二个元素值,int型为4字节;
  6. sizeof(a + 1),由于a没有单独在括号中,其相当于第一行首元素的地址,a+1相当于第二行首元素的地址,地址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并没有访问其内存,只是计算大小)。

的地址,地址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并没有访问其内存,只是计算大小)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值