一:本文简介:
首先,介绍一下该类型笔试题的考查方式:该类型题目一般考察通过sizeof()和strlen对与数组,指针相关的,不同类型的数据进行空间长度或元素个数的计算。由于初学者在指针和数组的学习中,相应概念易混淆,故该类型笔试题易出错。下面,我将就此讲解原理,梳理概念并对相应题型分类讲解。
二:相应概念原理:
1.在C语言中,sizeof()并非函数,它是一个C语言关键字(单目操作符),是一个用于判断某种数据类型长度或者某种表达式长度 (所占内存空间大小)(单位是一个字节)的运算符。
sizeof()不在乎内存中存放的是什么,只在乎内存大小。
注:sizeof计算数组或者字符串所占内存空间大小包含末尾的'\0'.
2.在 C语言中,strlen()是头文件#include<string.h>下的一个库函数,功能是计算一个字符串的长度,直到遇到'\0'停止,不包含'\0'.
strlen()函数的括号中需要传参类型是const char*(常量字符指针类型),该函数的返回值类型是size_t(无符号整型)。
strenlen函数求字符串长度,从给定的地址向后访问字符,统计'\0'之前出现的字符个数(字节数)
(注:由于strlen函数返回值类型是无符号整型,因此,在某些类型的笔试题中,应注意strlen函数的返回值用于加减的一些情况。)
3.一些归总:对于一个数组:数组名和数组首元素地址和取地址数组名的值都是相同的 :即arr = &arr[0] = &arr。
但是意义不同 :&arr表示对整个数组取地址 ,arr或者&arr[0]则表示对数组首元素取地址。
数组名+1加的是数组单个元素大小的字节数 ,而取地址数组首元素+1加的是数组中单个元素大小的字节数 , 取地址数组名+1加的是所有数组元素总共的字节数。
4.数组名通常来说是数组首元素的地址,但有两个特例:
一:sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小。
二:&数组名(取地址数组名),取出的是整个数组的地址。
5.在X86平台(32位)中,地址所占内存空间大小为4个字节,在X64平台(64位)中,地址所占内存空间大小为8个字节。只要是地址,所占内存空间大小就是4或8个字节。
6.二维数组的理解:将二维数组想象成一维数组,每一行都是一个一维数组,char *p = arr( 数组名) , 则arr[i][j]=*(*(p+i)+j).
三:题目分类:
一.sizeof与一维数组
二.sizeof与字符数组
三.strlen与字符数组(大括号初始化)
四.strlen,sizeof与字符数组(“双引号初始化)
五.sizeof,strlen与字符指针
六.sizeof与二维数组
四:题目讲解:
(相应头文件及主函数名,括号已省略)
一.
1.例题:
int a[]={1,2,3,4};
1 printf("%d\n",sizeof(a));
2 printf("%d\n",sizeof(a+0));
3 printf("%d\n",sizeof(*a));
4 printf("%d\n",sizeof(a+1));
5 printf("%d\n",sizeof(a[1]));
6 printf("%d\n",sizeof(&a));
7 printf("%d\n",sizeof(*&a));
8 printf("%d\n",sizeof(&a+1));
9 printf("%d\n",sizeof(&a[0]));
10 printf("%d\n",sizeof(&a[0]+1));
2.解析:
1 sizeof(a)计算整个数组的大小,该数组有4个整形元素,一共4*4=16个字节。
2 sizeof(a+0)这里sizeof的括号内不再是数组名了,这里的a表示数组首元素地址,a+0仍是数组首元素地址,而地址所占内存大小为4或8个字节。
3 sizeof(*a)a表示数组首元素地址,*a表示数组的第一个元素,该数组的第一个元素为整型,所占内存大小为4个字节。
4. sizeof(a+1)a表示数组首元素地址,a+1表示数组第二个元素的地址,sizeof(a+1)就是数组第二个元素的地址的大小,所占内存大小为4或8个字节。
5. sizeof(a[1]) a[1]是数组的第二个元素,也为整型,大小为四个字节。
6. sizeof(&a) &a是数组的地址,只要是地址,所占内存大小就是4或8个字节。
7. sizeof(*&a) a取地址再解引用等价于a本身,因此 sizeof(&*a)==sizeof(a)==16
8. sizeof(&a+1) &a表示数组的地址,+1跳过整个数组,指向原数组最后一个元素后的地址,而只要是地址,所占内存空间大小就是4或8个字节。
9. sizeof(&a[0]) 表示数组首元素地址,大小为4或8字节。
10. sizeof(&a[0]+1)数组首元素地址+1指向数组第二个元素的地址,大小为4或8字节。
二.
1.例题:
char arr[]={'a','b','c','d','e','f'};
1. printf("%d\n",sizeof(arr));
2. printf("%d\n",sizeof(arr+0));
3. printf("%d\n",sizeof(*arr));
4. printf("%d\n",sizeof(arr[1]));
5. printf("%d\n", sizeof(&arr));
6. printf("%d\n", sizeof(&arr+1));
7. printf("%d\n", sizeof(&arr[0]+1));
2.解析:
1. sizeof(arr) 该数组一共六个字符元素元素,每个元素占一个字节,因此该数组占六个字节。
2. sizeof(arr+0) arr+0是首元素地址,占4或8个字节。
3. sizeof(*arr)arr为首元素地址,*arr为首元素,占一个字节。
4. sizeof(arr[1]) arr[1]是数组的第二个元素,大小为一个字节。
5. sizeof(&arr) &arr是该数组的地址,占4或8个字节。
6. sizeof(&arr+1) 数组地址+1表示跳过整个数组后的地址,大小为4或8个字节。
7. sizeof(&arr[0]+1) &arr[0]+1表示数组第二个元素的地址,大小为4或8个字节。
三.
1.例题:
#include<string.h>
char arr[]={'a','b','c','d','e','f'};
//该初始化方式意味着该数组中有且仅有六个字符元素,无'\0';
1. printf("%d\n",strlen(arr));
2. printf("%d\n",strlen(arr+0));
3. printf("%d\n",strlen(*arr));
4. printf("%d\n",strlen(arr[1]));
5. printf("%d\n", strlen(&arr));
6. printf("%d\n", strlen(&arr+1));
7. printf("%d\n", strlen(&arr[0]+1));
2.解析:
1 strlen(arr) arr表示首元素地址,strlen(arr)表示从首元素地址开始,求直到'\0'之前的元素个数。arr数组中不包含'\0',strlen会继续向后寻找'\0',统计'\0'之前出现的字符个数。因此结果为>=6的随机值。
2 strlen(arr+0) arr+0仍为数组首元素地址,结果仍为随机值。
3 strlen(*arr) *arr是数组的首元素,是字符'a'。 字符'a'的ascii值为97,被 strlen函数当作地址并求从该地址开始直到'\0'之前的元素个数,导致访问出错。
4 strlen(arr[1]) arr[1]是数组的第二个元素,是字符'b'。 字符 'b'的ascii码值为98,被strlen函数当作地址并求从该地址开始直到'\0'之前的元素个数,导致访问出错。
5 strlen(&arr) &arr表示整个数组的地址,相当于数组的首元素地址,结果为随机值(参考 1)
6 strlen(&arr+1) &arr+1指向跳过一个数组长度后的地址,结果仍为随机值,该随机值与1和5中的随机值相差6(跳过一个该数组跳过6个元素)。
7 strlen(&arr[0]+1) &arr[0]+1表示数组第二个元素额地址,即字符'b'的地址,结果仍为随机值且该随机值比1中求得随机值小1,解析原理与1相同。
四.
1.例题:
#include<string.h>
char arr[]=“abcef"
1. printf("%d\n",sizeof(arr));
2. printf("%d\n",sizeof(arr+0));
3. printf("%d\n",sizeof(*arr));
4. printf("%d\n",sizeof(arr[1]));
5. printf("%d\n", sizeof(&arr));
6. printf("%d\n", sizeof(&arr+1));
7. printf("%d\n", sizeof(&arr[0]+1));
8. printf("%d\n",strlen(arr));
9. printf("%d\n",strlen(arr+0));
10. printf("%d\n",strlen(*arr));
11. printf("%d\n",strlen(arr[1]));
12. printf("%d\n", strlen(&arr));
13. printf("%d\n", strlen(&arr+1));
14. printf("%d\n", strlen(&arr[0]+1));
2.解析:
"abcdef" <=> [a b c d e f \0]
1 sizeof(arr) 数组7个元素,7*1=7。
2 sizeof(arr+0) arr+0为数组首元素地址,4或8个字节。
3.sizeof(*arr) *arr为数组首元素,是字符'a',长度为一个字节。
4 sizeof(arr[1]) arr[1]为数组第二个元素,是字符'b',长度为一个字节。
5 sizeof(&arr) &arr为整个数组地址,大小为4或8个字节。
6 sizeof(&arr+1)&arr=1表示'\0'之后的地址,大小为4或者8个字节。
7 sizeof(&arr[0]+1) &arr[0]+1表示该数组第二个元素的地址,大小为4或8个字节。
8 strlen(arr)该数组中存在'\0',该数组中'\0'之前有六个字符(六个字节),因此返回值为6.
9 strlen(arr+0) arr+0表示首元素地址,函数返回值仍为6.
10 strlen(*arr) *arr表示首元素,即字符'a',ascii码值为97,为非法访问内存,访问出错。
11 atrlen(arr[1]) arr[1]表示第二个圆度,即字符'b',ascii 码值为97,为非法访问内存,会导致访问出错。
12 strlen(&arr) &arr为整个数组地址,也从首元素地址开始向后数字符,返回值为6.
13 strlen(&arr+1)从'\0'之后开始数字符,无法确定之后'\0'的位置,答案为随机值。
14 strlen(&arr[0]+1) &arr[0]+1表示第二个元素的地址,strlen(&arr[0]+1)表示从第二个元素(字符'b'开始向后数直到遇见'\0',一共五个元素,返回值为5.
五.
1.例题:
char* p="abcdef"
(注:该写法表示字符指针p中存放的是该字符串首元素字符'a'的地址)
1 printf("%d\n",sizeof(p));
2 printf("%d\n",sizeof(p+1));
3 printf("%d\n",sizeof(*p);
4 printf("%d\n",sizeof(p[0]));
5 printf("%d\n",sizeof(&p);
6 printf("%d\n",sizeof(&p+1);
7 prntf("%d\n",sizeof(&p[0]+1);
8 printf("%d\n",strlen(p));
9 printf("%d\n",strlen(p+1));
10 printf("%d\n",strlen(*p);
11 printf("%d\n",strlen(p[0]));
12 printf("%d\n",strlen(&p);
13 printf("%d\n",strlen(&p+1);
14 prntf("%d\n",strlen(&p[0]+1);
2.解析:
1 sizeof(p) p是指针变量,计算的是指针变量的大小,为4或8个字节。
2 sizeof(p+1) p+1为第二个字符(字符 ’b'的地址),大小为4或8个字节。
3 sizeof(*p) *p表示字符'a',大小为一个字节。
4 sizeof(p[0]) p[0] <=> *(p+0) <=> *p 表示字符'a',大小为一个字节。
5 sizeof(&p) &p是指针变量p的地址,大小为4或8个字节。
6 sizeof(&p+1) &p+1表示p的地址跳过一个字节之后的地址,大小仍为4或8个字节。
7 sizeof(&p[0]+1) &p[0]+1表示字符'b'的地址,大小为4或8个字节。
8 strlen(p) p存放的是'a'的地址,该字符串末尾存在'\0',因此函数返回值==6.
9 strlen(p+1) p+1存放字符'b'的地址,函数返回值==5.
10 strlen(*p) *p和p[0]都表示字符串首元素字符'a',ascii码值为97,被strlen视为内存(strlen的输入
11 strlen(p[0]) 参数应为char*类型, 97为非法访问内存,访问出错。
12 strlen(&p) &p是指针p的地址,之后'\0'的位置未知,因此返回值为随机值。
13 strlen(&p+1) &p+1是指针p的地址跳过4或8个字节后的地址,函数返回值仍为随机值。
14 strlen(&p[0]+1) &p[0]表示'a'的地址,+1表示'b'的地址,返回值为5.
六.
1.例题:
int a[3][4] = {0};
1 printf("%d\n",sizeof(a));
2 printf("%d\n",sizeof(a[0][0]));
3 printf("%d\n",sizeof(a[0]));
4 printf(”%d\n",sizeof(a[0]+1));
5 printf("%d\n",sizeof(*(a[0]+1)));
6 printf("%d\n",sizeof(a+1));
7 printf("%d\n",sizeof(*(a+1));
8 printf("%d\n",sizeof(&a[0]+1));
9 printf("%d\n",sizeof(*(&a[0]+1)));
10 printf("%d\n",sizeof(*a));
11 printf("%d\n",sizeof(a[3]));
2.解析:
1 sizeof(a) 计算整个数组大小,单位是字节。3*4*4=48占48个字节大小的内存
2 sieof(a[0][0]) 计算第一行第一列元素的大小, 为整型,占四个字节。
3 sizeof(a[0]) a[0]是第一行的数组名,它单独放在sizeof()的括号内,计算的是第一行的大小,sizeof(a[0])计算的是第一行这一整个一维数组的大小,占4*4=16个字节。
4 sizeof(a[0]+1) a[0]是第一行这个一维数组的数组名,这个数组名并没有单独放在sizeof()的括号内,那么就表示第一行第一个元素的地址,+1则表示第一行第二个元素的地址,是地址那么所占内存空间就是4或8个字节。
5 sizeof(*(a[0]+1)) a[0]+1表示第一行第二个元素的地址,解引用表示第一行第二个元素,是一个整型元素,占4个字节。
6 sizeof(a+1) a表示首元素地址,就是第一行的地址,(a+1)则表示第二行的地址,占4或8字节。
7 sizeof(*(a+1)) 解引用第二行的地址访问的就是第二行,占4*4=16个字节
(sizeof(*(a+1) <=> sizeof(a[1])计算的是第二行的大小,占16个字节)
8 sizeof(&a[0]+1) a[0]是第一行的数组名,&a[0]+1表示第二行的地址,占4或8字节。
9 sizeof(*(&a[0]+1)) &a[0]+1是第二行的地址,解引用找到第二行,占4*4=16个字节。
10 sizeof(*a) a就是首元素(第一行的地址) *a表示第一行,占16个字节(sizeof(*a)<=>sizeof(a[0]))
11 sizeof(a[3])
乍一看越界访问了,但是我们只需要判断a[3]是什么数据类型即可求出其所占内存大小。
a[3]是数组名,类型是int a[4],占4*4=16个字节。