经典笔试题:指针详解

来源:互联网 发布:linux系统哪个版本好 编辑:程序博客网 时间:2024/06/05 10:58

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

原创粉丝点击