• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

超详细理解数组和指针

互联网 diligentman 3小时前 3次浏览

本篇代码均在32位系统下
只要是指针类型,不管是什么类型,在同一个系统下,占用的内存空间都相同

通过sizeof和strlen来加深我们对指针和数组的理解:

sizeof,
sizeof是一个运算符,它的作用是取一个对象(数据类型或者数据对象)的长度(即占用内存的大小,是以字节为单位的) 使用sizeof,一定要关注类型~

strlen,size_t strlen ( const char * str )
计算字符串的长度是一种函数。C字符串的长度等于字符串开头和终止空字符之间的字符数(不包括终止空字符本身),返回值是字符串长度,使用strlen函数,需要包含头文件string.h

一维数组

int a[ ] = { 1,2,3,4 };

1.printf("%dn", sizeof(a));        //16
2.printf("%dn", sizeof(a + 0));    //4
3.printf("%dn", sizeof(*a));       //4
4.printf("%dn", sizeof(a + 1));    //4
5.printf("%dn", sizeof(a[1]));     //4
  1. (a),表示a[ ]数组,int占4个字节,一共有4个元素,即4个int,故为:4×4=16
  2. (a+0),数组不能进行+运算,隐式转成了指针,为int * 类型,故为:4
  3. (*a),数组不能解引用,隐式转成指针,为int * 类型,再解引用,得到int类型,故为:4
  4. (a+1),和第2个一样,为int * 类型,故为:4
  5. (a[1]),a[1]得到数组中的’2’这个元素,为int类型,故为:4
6.printf("%dn", sizeof(&a));       //4
7.printf("%dn", sizeof(*&a));      //16
8.printf("%dn", sizeof(&*a));      //4
9.printf("%dn", sizeof(&a + 1));   //4
10.printf("%dn", sizeof(&a[0]+1)); //4
  1. (&a),表示数组指针,为int(*)[4] 类型,也是指针,故为:4
  2. (*&a),先&a,得到int *[4] ,是数组指针,再解引用,便还原到int[4],就是一个数组,故为:4×4=16
  3. (&*a),先 *a,得到一个int,再&,得到int *,故为:4
  4. (&a),得到一个数组指针,再+1,还是数组指针,故为:4
  5. (&a[0]+1),a[0],得到int型,&a[0],得到int*,再+1,仍为int*,故为:4

字符数组

char arr[ ]={ ‘a’,‘b’,‘c’,‘d’,‘e’,‘f’ };

1.printf("%dn", sizeof(arr));        //6
2.printf("%dn", sizeof(arr + 0));    //4
3.printf("%dn", sizeof(*arr));       //1
4.printf("%dn", sizeof(arr[1]));     //1 
5.printf("%dn", sizeof(&arr));       //4
6.printf("%dn", sizeof(&arr + 1));   //4
7.printf("%dn", sizeof(&arr[0] + 1));//4
8.printf("%dn", sizeof(*&arr));      //6
9.printf("%dn", sizeof(&*arr));      //4
  1. (arr),表示arr[ ],整个char数组里有6个元素,故为:6
  2. (arr+0),数组不能进行+运算,隐式转成了指针,为char* 类型,故为:4
  3. (*arr),数组不能解引用,隐式转成指针,为char * 类型,再解引用,得到char类型,故为:4
  4. arr[1],得到字符b,故为1
  5. &arr,得到一个数组指针,类型是char(*)[6],还是指针,故为:4
  6. (&arr+1),和5一样,为数组指针类型,故为:4
  7. (&arr[0]+1),先[0],得到char类型,再&,得到一个char*,再+1,仍为指针,故为:4
  8. (*&arr),先&arr,得到char( *)[6],再解引用,得到char[6],故为:6×1=6
  9. (&*arr),先 *arr,得到char,再&,得到char *,故为:4
1.printf("%dn", strlen(arr));
2.printf("%dn", strlen(arr + 0));
3.printf("%dn", strlen(*arr));
4.printf("%dn", strlen(arr[1]));
5.printf("%dn", strlen(&arr));
6.printf("%dn", strlen(&arr + 1));
7.printf("%dn", strlen(&arr[0] + 1));
  1. 上述为未定义行为,因为arr数组中没有 ‘’
  2. arr+0,到a,从a开始找,仍无’’,故仍为未定义行为
  3. strlen的类型是const char*,而*arr的类型是char,类型不匹配,编译不通过(弱类型C语言可以编译运行,发生隐式类型转换)
  4. arr[1],得到字符b,为char类型,与strlen类型不匹配
  5. &arr,得到数组指针,与strlen类型不匹配,在C语言中,会发生隐式类型转换,把数组指针传换成char*,仍找不到’’,故仍为未定义行为
  6. 未定义行为,&arr,得到数组指针,再+1,跳过整个数组,下标越界
  7. arr[0],得到char,再&,得到char*,再+1,得到b,从b往后找,仍无’’,故为未定义行为

只要当前字符数组不是字符串,就不能使用str系列的函数~

char a[ ] = “abcdef”;

1.printf("%dn", sizeof(a));        //7
2.printf("%dn", sizeof(a + 0));    //4
3.printf("%dn", sizeof(*a));       //4
4.printf("%dn", sizeof(a[1]));     //1
5.printf("%dn", sizeof(a[1] + 1)); //4
6.printf("%dn", sizeof(&a));       //4
7.printf("%dn", sizeof(&a + 1));   //4
8.printf("%dn", sizeof(&a[0] + 1));//4
9.printf("%dn", sizeof(*&a));      //7
10.printf("%dn", sizeof(&*a));     //4
  1. (a),表示a[ ],为char类型,包含’’,故为:6+1=7
  2. 数组不能+运算,隐士转换成指针,为char*类型,故为:4
  3. *a,得到字符a,为char类型,故为:1
  4. a[1],得到一个char,故为:1
  5. a[1],得到一个字符b,为char,再+1,即char和int进行运算,触发整型提升,结果为int,故为:4
  6. &a,得到数组指针,为char(*)[7]类型,也为指针,故为:4
  7. (&a+1),&a,得到一个数组指针,再+1,仍为数组指针,故为:4
  8. a[0],得到字符a,为char,再&,得到char*,再+1,仍为char*,故为:4
  9. *&a,先&a,得到一个数组指针,为char( *)[7],再 *,得到char[7],故为:7
  10. &*a,先 *a,得到一个char,再&,得到一个char *,故为:4
1.printf("%dn", strlen(a));        //6
2.printf("%dn", strlen(a + 0));    //6
3.printf("%dn", strlen(*a));       //编译不通过
4.printf("%dn", strlen(a[1]));     //编译不通过
5.printf("%dn", strlen(&a));       //6
6.printf("%dn", strlen(&a + 1));   //未定义行为
7.printf("%dn", strlen(&a[0] + 1));//5
  1. a是字符数组表示字符串,故为:6
  2. 从字符a开始往后找’’,找6步,故为:6
  3. *a,得到字符a,为char类型,类型不匹配,编译不通过
  4. a[1],得到字符a,为char类型,类型不匹配,编译不通过
  5. &a,得到数组指针,与strlen的类型不匹配(理论来说编译应该不通过),但在C语言中会触发隐士类型转换,转成char*,从a往后找,6步找到’’,故为:6
  6. &a,得到数组指针,再+1,要跳过这个数组,下标越界,故为未定义行为
  7. a[0],得到字符a,再&,得到char*,+1,指向字符b,从b开始找’’,需要5步,故为:5

char* p = “abcdef”;

1.printf("%dn", sizeof(p));         //4 
2.printf("%dn", sizeof(p + 1));     //4 
3.printf("%dn", sizeof(*p));        //1
4.printf("%dn", sizeof(p[0]));      //1
5.printf("%dn", sizeof(&p));        //4
6.printf("%dn", sizeof(&p + 1));    //4
7.printf("%dn", sizeof(&p[0] + 1)); //4
  1. p的类型是char*,故为:4
  2. p是char*,再+1,仍为char*,故为:4
  3. *p,是char类型,故为:1
  4. p[0],得到一个char,故为:1
  5. &p,得到char**类型,故为:4
  6. &p,得到char** 类型,+1仍为char**,故为:4
  7. p[0],得到char,再&,得到char*,+1仍为char*,故为:4
1.printf("%dn", strlen(p));        //6
2.printf("%dn", strlen(p + 1));    //5
3.printf("%dn", strlen(*p));       //编译出错
4.printf("%dn", strlen(p[0]));     //编译出错
5.printf("%dn", strlen(&p));       //编译出错
6.printf("%dn", strlen(&p + 1));   //编译出错
7.printf("%dn", strlen(&p[0] + 1));//5
  1. p,指向字符a,往后找’’,需6步,故为:6
  2. (p+1),指向字符b,往后找’’,需5步,故为:5
  3. *p,得到char,strlen的类型是const char *,类型不匹配,编译出错
  4. p[0],得到char,strlen的类型是const char *,类型不匹配,编译出错
  5. &p,得到char**,与strlen类型不匹配,编译出错
  6. (&p + 1)),同5
  7. p[0],得到char,再&,得到字符a,+1,得到字符b,往后找’’,5步,故为:5

二维数组

int a[3][4] = { 0 };
长度为3,里面的每个元素的长度又为4

1.printf("%dn", sizeof(a));            //48
2.printf("%dn", sizeof(a[0][0]));      //4
3.printf("%dn", sizeof(a[0]));         //16
4.printf("%dn", sizeof(a[0] + 1));     //4
5.printf("%dn", sizeof(*a[0] + 1));    //4
6.printf("%dn", sizeof(a + 1));        //4
7.printf("%dn", sizeof(*(a + 1)));     //16
8.printf("%dn", sizeof(&a[0] + 1));    //4
9.printf("%dn", sizeof(*(&a[0] + 1))); //16
10.printf("%dn", sizeof(*a));          //16 
11..printf("%dn", sizeof(a[3]));       //16
  1. (a),二维数组一共12个元素,12×4=48字节,故为:48
  2. a[0][0],取到第0行第0列的元素,故为:4
  3. a[0],即得到int[4],故为:4×4=16
  4. a[0],得到int[4],数组不能+1,隐士转成指针,为int*,故为:4
  5. a[0],得到int[4],+1,隐士转成int*,再*,得到int,故为:4
  6. a为int[3][4]类型,+1,得到int(*)[4],故为:4
  7. a+1得到int(* )[4],再*,得到int[4],故为:4×4=16
  8. a[0],得到int[4],再&,得到int(* )[4],+1,仍为int(*)[4],故为:4
  9. &a[0] + 1,同上,得到nt(*)[4],再 *,得到int[4],故为:4×4=16
  10. *a,相当于隐士转成指针后再解引用,*a等价于a[0],类型是int[4],故为:4×4=16
  11. 看起来a[3]越界,但由于sizeof是编译期求值,而越界是发生在运行期,当这个代码编译完毕,等价于转换成:printf("%dn",16),故为:16

*(a+1) 等价于 a[1]

sizeof和strlen的区别

sizeof是一个关键字,而strlen是函数
sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以’’’'结尾的。
strlen的结果要在运行的时候才能计算出来,是用来计算字符串的长度,不是类型占内存的大小,而sizeof是编译期求值
sizeof只关心这块内存的大小,不关心这块内存存放了什么数据,而strlen关心这块内存存放的数据,不关心这块内存的大小,直到遇到第一个为止。

不同的参数,sizeof的返回值

数组 编译时分配的数组空间大小
指针 存储该指针所用的空间大小(在32位系统是4,在64系统是8)
对象 对象的实际占用空间大小
类型 该类型所占的空间大小
函数 函数的返回类型所占的空间大小。函数的返回类型不能是void

程序员灯塔
转载请注明原文链接:超详细理解数组和指针
喜欢 (0)