数组与指针笔试题详解(指针学习必看的习题)

(。・∀・)ノ゙嗨你好这里是ky233的主页:ky233的主页点这里

点个关注不迷路⌯'▾'⌯

解析大纲~

一、数组部分

1.一维数组的的习题

2.字符数组的练习

2.二维数组的习题

二、指针笔试题

1.程序的结果是什么?

2.假设p 的值为0x100000。 如下表达式的值分别为多少?

3.笔试题3

4.笔试题4

5.笔试题5

6.笔试题6

7.笔试题7

8.笔试题8


一、数组部分

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。

至此,这次的练习已经全部解析完成。

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值