C语言指针笔试题详解

这篇博客主要探讨了C语言中的指针操作和结构体对齐规则。通过多个示例,解释了指针如何在数组、结构体和不同类型转换中移动,以及结构体内部成员的对齐方式。文章还提供了具体的代码实例,演示了指针加减运算和数组地址的计算。此外,还介绍了结构体对齐的默认规则和#pragma pack宏的影响。
摘要由CSDN通过智能技术生成

目录

前言

一、运行结果?

二、运行结果?

1.结构体对齐规则

2.运行结果

三、运行结果?

 四、运行结果?

 五、运行结果?

 六、运行结果

 七、运行结果?

 八、运行结果

总结

前言

        C语言指针笔试题

一、运行结果?

#include<stdio.h>
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得到的是数组的地址,&a+1,跳过整个数组,用ptr指向这个位置,ptr-1指向上图位置,然后解引用得到后的int类型的数据,得到5

二、运行结果?

1.结构体对齐规则

一、结构体对齐规则首先要看有没有用#pragma pack宏声明,这个宏可以改变对齐规则,
有宏定义的情况下结构体的自身宽度就是宏上规定的数值大小,所有内存都按照这个宽度去布局,
#pragma pack 参数只能是 '1', '2', '4', '8', or '16'。
二、在没有#pragma pack这个宏的声明下,遵循下面三个原则:
1、第一个成员的首地址为0.
2、每个成员的首地址是自身大小的整数倍
3、结构体的总大小,为其成员中所含最大类型的整数倍。

2.运行结果

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

1)首先定义了一个结构体类型的指针p,即p的类型为(struct Test*),现在让p的地址是0x100000,本题考察点就是指针+1跳过了几个字节,指针+1取决于类型,int* +1 跳过4个字节,char* +1 跳过1个字节

2)p的类型为(struct Test*),所以 + 1后跳过20个字节,0x100000,指针+1,跳过20个字节,那就是0x100014,14(16进制)->20(十进制);

3)进行(unsigned long)强制类型转换后,p变为了一个普通的整形数字,数字+1后就是加1变成0x100001,对于整形+1,相当于向后走了一个字节,因为数字+1,相当于地址本来是0x10的地址+1,我们将10变成十进制是16,16+1就是17,而17其实就是0x11,其实就是0x10直接+1就行,因为1*16^0 = 1。一个字节差一个地址,在内存单元中,一个地址给一个编号。其0x16和0x17差一个地址,其实际就是差一个字节;

4)在进行(unsigned int*)强制类型转换后,加1跳过一个整型的大小,即4个字节。

struct Test
{
    int Num;
    char* pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p;
int main()
{
    p = 0x100000;
    printf("%x\n", p + 0x1);//%p是以地址的形式打印,%x打印16进制,但省略高位的0
    printf("%p\n", (unsigned long)p + 0x1);
    printf("%p\n", (unsigned int*)p + 0x1);
    return 0;
}

三、运行结果?

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);
	//ptr1跳过了整个数组
	//ptr1[-1]->ptr1[0+(-1)]->*(ptr1-1)->4->0x4
	
	return 0;
}

 四、运行结果?

#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
//注意逗号表达式
	int* p;
	p = a[0];//a[0]代表的就是第一行的地址,与第一行第一个元素地址相同
	printf("%d", p[0]);//1->*(p+0)->*p
	return 0;
}

 五、运行结果?

int main()
{
	int a[5][5];
	int(*p)[4];//定义一个指针,指针指向一个数组,数组有4个元素,元素都是int类型的
	p = a;//然后该指针存放二维数组的地址
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);

	return 0;
}

        假设有 a[n] ,表示a向下偏移n行后的地址;

        假设有*(a+n),表示向下偏移n行后的地址;

 六、运行结果

 注意类型:

 输出结果:

 七、运行结果?

先看char *a[] :
        由于[] 的优先级高于 * 所以a先和 []结合,他还是一个数组,数组中的元素才是char * ,char * 是一个变量,保存的地址。

char *a[] = {"China","French","America","German"};

        通过这句可以看到, 数组中的元素是字符串,那么sizeof(a) 是多少呢,有人会想到是五个单词的占内存中的全部字节数 6+7+8+7 = 28;但是其实sizeof(a) = 16;

        为什么, 字符串常量的本质是地址,a 数组中的元素为char*指针,指针变量占四个字节,那么四个元素就是16个字节了。

#include <stdio.h>
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);//at
	return 0;
}

 八、运行结果


int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);//%s输出字符串的时候遇到0或‘\0’,就会被截断,只输出0或‘\0’前面的字符
	printf("%s\n", *-- * ++cpp + 3);
	printf("%s\n", *cpp[-2] + 3);
	printf("%s\n", cpp[-1][-1] + 1);
	return 0;
}

  注意:cpp[-2]我们可以把它当做解引用,并没有做运算,所以cpp的值,还会延续第三步结束时的值。

总结

        指针笔试题,值得反复去看,一篇足够!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值