(。・∀・)ノ゙嗨你好这里是ky233的主页:ky233的主页点这里
点个关注不迷路⌯'▾'⌯
解析大纲~
2.假设p 的值为0x100000。 如下表达式的值分别为多少?
一、数组部分
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));
1:16,在sizeof里只有一个数组名表示的是整个数组的地址,这个数组里有四个元素,类型是int,所以每个元素是4个字节。
2:4,这里的a表示的是首元素地址,a加0表示的是第一个元素的地址,所以是4个字节。
3:4,a代表着首元素地址,所以*a是1,所以是四个字节。
4:4,a是首元素地址,a+1是第二个元素的地址。
5:4,a[1]可以写成*(a+1),指向的是2,计算的是第二个元素的大小,所以是4个字节。
6:4,&a代表着是整个数组的地址,但只要是地址就是4或者8字节。
7:16,计算的是整个元素的大小。
8:4,得到的是数组后面的地址,但也是地址
9:4,a[0]是数组的第一个元素,取地址,就是地址。
10:4,第一个元素的地址加1个整形的字节,是第二个元素的地址。
2.字符数组的练习
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));
1:6,单独放一个数组名,计算的是整个数组的大小,一共是6个字符,所以是6个字节。
2:4,arr+0是首元素的地址。
3:1,*arr是首元素所指向的字符a
4:1,arr[1]可以写成*(arr+1),所以是b,所以是一个字符。
5:4,整个字符数组的地址。
6:4,数组后面的地址,同样是地址。
7:4,是第二个元素的地址,但同样是地址
char arr[] = {'a','b','c','d','e','f'};
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));
1:大于6的随机值,因为strlen函数是计算\0前面的元素个数,但数之中没有\0。
2:大于6的随机值,同上;
3:程序错误,形成了非法访问,arr是数组首元素的地址,*arr是数组的首元素,“a'-97,strlen把97当成了地址,但没有权限访问。
4:程序错误,形成了非法访问,同上。
5:大于6的随机值,同1
6:随机值(随意数),同1
7:大于5的随机值,同1
char arr[] = "abcdef";
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))
1:7,最后由\0,所以是7个字节。
2:4,arr+e是数组首元素的地址。
3:1, *arr表示的是数组的首元素。
4:1,arr[1]数组的第二个元素。
5:4,&arr数组的地址,但是数组的地址依然是地址。
6:4,&arr + 1是0后边的这个地址。
7:4, &arr[0] + 1是数组第二个元素的地址。
char arr[] = "abcdef";
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));
1:6,字符串最后默认加上\0。
2:6,同上
3:错误的,*arr此时是a,Assic码值是97。
4:同上。
5:6,&arr代表着字符串arr的地址。
6:随机值。
7 :5,从第二个字符开始算之后有多少。
char *p = "abcdef";
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.printf("%d\n", sizeof(&p[0]+1));
1:4,p是指针变量,计算的是指针变量的大小
2:4, p+1是'b'的地址
3:1, *p其实就是'a'
4:1, p[0]等于 *(p+0)等于*p
5:4,&p是指针变量p在内存中的地址
6:4,&p+1是跳过p之后的地址
7:4,&p[0]是a的地址,&p[0]+1就是b的地址
char *p = "abcdef";
1.printf("%d\n", strlen(p));
2.printf("%d\n", strlen(p+1));
3.printf("%d\n", strlen(*p));
4.printf("%d\n", strlen(p[0]));
5.printf("%d\n", strlen(&p));
6.printf("%d\n", strlen(&p+1));
7.printf("%d\n", strlen(&p[0]+1));
1:6,字符串最后默认加上\0。
2:5,从b开始数字符。
3:错误的,*p此时是a,Assic码值是97。
4:同上。
5:随机值,取地址p是p的地址,与原字符串没关系了。
6:随机值,&p+1是跳过p之后的地址。同样与原字符串没有关系。
7:5,和第二题是一个意思,
2.二维数组的习题
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)));
10printf("%d\n",sizeof(*a));
11.printf("%d\n",sizeof(a[3]));
1:48,3*4*4,计算的是整个数组的大小。
2:4,第1行第一个元素的大小。
3:16,a[0]是第一行的数组名,sizeof(a[0])就是第一行的数组名单独放在sizeof内部,计算的是第一行的大小。
4:4,a[0]就是数组首元素的地址,就是第一行第一个元素的地址,a[0]+1就是第一行第二个元素的地址。
5:4 ,*(a[0] + 1))表示的是第一行第二个元素。
6:4 ,a表示首元素的地址,a是二维数组,首元素的地址就是第一行的地址,所以a表示的是二维数组第一行的地址,a+1就是第二行的地址。
7:16,对第二行的地址解引用访问到就是第二行。
8:4,a[0]是第一行的数组名,&a[0]取出的就是第一行的地址,&a[e] + 1 就是第二行的地址。
9:16, 对第二行的地址解引用访问到就是第二行。
10:16, a就是首元素的地址,就是第一行的地址,*a就是第一行。
11:16,虽然数组中没有没有第三行数组,但是,sizeof是靠类型,判断字节大小的,类型是int [4]。
数组名的意义:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。
二、指针笔试题
1.程序的结果是什么?
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
首先,&a+1指向的是数组后面的地址,所以ptr里面放的也是数组后面的地址,a+1是数组第二个元素的地址,解引用就是2,ptr-1则是 数组后面的地址减一个字节,则是5。
2.假设p 的值为0x100000。 如下表达式的值分别为多少?
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
int main()
{
p = (struct Test*)0x100000;
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
首先,第一个,0x是十六进制的表示方法,这个结构体站20个字节,所以加上1是跳过整个结构体,就是加上20个字节,又因为%p是打印地址,在32位的环境下应该是32位字节,转换为十六进制则应该是00100014;第二个,p被转化为了整数,整数加1就是加1,所以结果应该是00100001;第三个,p被转化为了int*类型,所以应该是加4,所以结果应该是00100004。
3.笔试题3
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf( "%#x,%#x", ptr1[-1], *ptr2);
return 0;
}
首先第一个,&a+1是数组后面的地址,所以ptr1里面放的是数组后面的地址,ptr1[-1]可以写成,*(ptr1-1),所以指向的是数组最后一个元素,解引用应该是4,用十六进制表示就是0x4,第二个先把a转换为int类型,所以a代表首元素地址,整数+1就是+1,所以代表着向后跳了一个字节,而vs编译器是小端存储,所以在内存中存储的应该是00000002,以小端的方法转化回来应该是,02000000,以十六进制的表示方法应该是0x2000000。
4.笔试题4
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}
这题最关键的是数组初始化里面是逗号表达式,所以这个二维数组里面放的其实是,{{1,3},{5,0},{0,0}};所以a[0]是第一行数组,p[0]则是第一行数组的第一个元素,应该是1。
5.笔试题5
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
首先,我们知道p的类型是int(*)[4],所以加1跳过四个字节,p=a,所以p和a的首元素地点一样。那么*(*(p+4)+2)和*(*(a+4)+2)取的地址如图所示,指针减指针所得的是两个指针之间的元素个数,又因为内存是从底到高排列的,小地址减去大地址,所以应该是-4,在内存中-4的补码,为11111111111111111111111111111100,以%p(地址)的形式打印就是,0xfffffff4,第二个是用%d的形式打印的则就是-4。
6.笔试题6
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
&aa+1指向的是这个数组后面的地址,所以ptr1放的是这个意思。*(aa+1)其中aa是第1行的地址,加1则是第2行的地址,解引用之后是第2行第一个元素,所以ptr2里放的是第2行首元素的地址,注:类型都被转换为了int*,所以之后都是+-整形字节,所以ptr1-1就是10,ptr2-1则是5。
7.笔试题7
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
因为a数组每个元素的类型是char*,所以里面放的是指针,也就是每个元素的首字母地址,pa=a,a是数组名,是首元素的地址,所以pa也指向a数组首元素地址,pa++,加一个元素指向的则是第二个元素的首元素地址,所以打印的应是“at”。
8.笔试题8
int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}
首先第一个,cpp开始指向cp数组的首元素位置,++则指向了第二个元素的位置,此时解引用,则找到了c+2这个地址,再次解引用则找到了c的第三个元素的地址,则就是POINT,注意,cpp的文职此时还是指向cp第二个元素的。
第二个,先++cpp,指向第三个元素,解引用找到了c+1,此时在--就变成了c的地址,也就是c首元素的地址,这时候在解引用就找到了ENTER,之后+3则从E的位置+3,也就是从第4个字符开始打印,也就是ER。
第三个前半部分可以理解成,*(*(cpp-2)),注,这是的cpp是不会变化位置的,那么我们按照之前的思路可以找到FITST,+3则和第二题的+3一样,所以打印的应是ST。
第四个前半部分同样可以转化为*(*(cpp-1)-1),这时我们可以找到NEW,之后+1,所以应该打印的是EW。
至此,这次的练习已经全部解析完成。