您的位置:首页 > 其它

经典笔试题:指针详解

2017-11-19 10:03 127 查看
1.下面代码输出结果是什么?

int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));

system("pause");
return 0;
}


解析:

* (a + 1):此处a代表数组首元素的地址,那(a + 1)就代表第二个元素的地址,* 解引用,* (a + 1) = 2。

*(ptr - 1): int *ptr = (int *)(&a + 1);
这行代码中 &a 代表 整个数组的地址,(&a + 1) 就代表数组a下一个int类型数字的地址,把这个地址强转成
int*
赋给ptr。这里(ptr - 1),指针减一就是减去它所指向的类型的大小,即往前移动四个字节,所以 *(ptr - 1) = 5。

答案:2 和 5

2.

struct Test
{
int Num;
char *pcName;
shortsDate;
charcha[2];
shortsBa[4];
}*p;


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

①p + 0x1= 0x___ ?

②(unsigned long)p + 0x1= 0x___ ?

③(unsigned int *)p + 0x1= 0x___ ?

解析:

①此处 p 是一个结构体指针,p+1实际上是要加上p所指向的类型的大小,而p指向的这个结构体的大小是20字节,所以第①题答案是:0x100014 (结构体大小计算详解请点击:博客Tianzez——内存对齐)

②把p强转成 unsigned long 类型,那这里就是一个无符号长整型数字加1,所以结果是:0x100001。

③把p强转成 unsigned int * 类型,此时p就是一个指针,指针加一就是加上它所指向的类型的大小,无符号长整型数据的大小是4,所以这里结果是:0x100004。

答案:①0x100014 ②0x100001 ③0x100004

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);

system("pause");
return 0;
}


解析:

① ptr1[-1] :
int *ptr1 = (int *)(&a + 1);
这行代码中 &a 代表整个数组的地址,(&a + 1) 就代表数组a下一个int类型数字的地址,把这个地址强转成 int * 赋给ptr,ptr 就指向尾元素a[3]下个元素的地址。ptr1[-1] 就相当于 *(ptr - 1)。所以最后结果是:0x000004。

② * ptr2:这里最后结果是:0x2000000 或 0x100。详解请点击:博客Tianzez——指针 地址强转的习题解析

答案:①0x000004 ②0x2000000 或 0x100

4.

int main(int argc, char * argv[])
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf("%d\n", p[0]);

system("pause");
return 0;
}


解析:

这里注意了,花括号里面是圆括号,所以这里就组成了逗号表达式。最后数组里面的值是 a[3][2] = {1, 3, 5, 0, 0, 0}; 所以a[0] = 1。

答案:1

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]);

system("pause");
return 0;
}


解析:



这道题只要能把内存布局图画出来就很简单了,做比较复杂的指针题时要学会画内存图,图画得越好,做题就更简单。

答案:FFFFFFFC 和 -4

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));

system("pause");
return 0;
}


解析:

① * (ptr1 - 1):
int *ptr1 = (int *)(&aa + 1);
这行代码中 &aa 代表整个数组的地址,(&aa + 1) 就代表数组a下一个int类型数字的地址,把这个地址强转成 int * 赋给ptr,这个时候ptr就指向数组 aa 尾元素 aa[2][5] 的下一个元素。然后(ptr1 - 1),此时 ptr 就指向aa[2][5]。*(ptr1 - 1) = 10。

② *(ptr2 - 1):
int *ptr2 = (int *)(*(aa + 1));
这行代码里 aa 代表数组首元素地址,而我们通常解决这类问题时:

把一个二维数组看做一个一维数组,这个一维数组的每个元素都是一个一维数组

那aa就代表二维数组里第一行的地址,(aa + 1)代表第二行的地址。* (aa + 1)表示整个第二行,而此时 (aa + 1) 做左值就表示第二行的地址,所以 (ptr2 - 1) = 5。

答案:①10 ②5

7.解释下面代码:

(1)(*( void(*) ()) 0)()
(2)void(*signal(int, void(*)(int)))(int);


解析:

(1)

  ①
void(*)()
是一个函数指针类型,这个函数无参数,无返回值。

  ②
(void(*)())0
把0强转成函数指针类型,0是一个函数的首地址。

  ③
(*(void(*)())0)
解引用,把地址为0的函数取出来。

  ④
(*(void(*)())0)()
调用这个地址为0的函数。

(2)

  ①对这块代码进行简化:
typedef void(* pfun_t)(int);


  ②
pfun_t signal(int, pfun_t)
:定义了一个函数指针 signal,指向的函数有两个参数,类型分别是 int 和 pfun_t 。

8.

int main()
{
char *a[] = { "work", "at", "alibaba" };
char **pa = a;
pa++;
printf("%s\n", *pa);

system("pause");
return 0;
}


解析:

char **pa = a;
此时pa是一个二级指针,
pa++;
实际上是pa加上它所指向的元素类型的大小,而pa指向的是一个 char * 类型指针,即pa = &a[0],
pa++
之后,pa = &a[1]。所以*pa = a[1],最后输出结果就是 “at” 。

答案: at

9.

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);

system("pause");
return 0;
}


解析:

请参照 :博客WangYe8613

答案:①PIONT ②ER ③ST ④EW
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: