【C语言】指针笔试题

1.

#include <stdio.h>
#include <string.h>
int main()
{
	//一维数组
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//4*4=16
	printf("%d\n", sizeof(a + 0));//首元素地址大小--4
	printf("%d\n", sizeof(*a));//首元素大小--4
	printf("%d\n", sizeof(a + 1));//第二个元素地址大小---4
	printf("%d\n", sizeof(a[1]));//第二个元素大小---4
	printf("%d\n", sizeof(&a));//数组地址的大小——4
	printf("%d\n", sizeof(*&a));//数组大小---16
	printf("%d\n", sizeof(&a + 1));//数组后空间地址的大小---4
	printf("%d\n", sizeof(&a[0]));//4
	printf("%d\n", sizeof(&a[0] + 1));//4

	//字符数组
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));//数组大小--6
	printf("%d\n", sizeof(arr + 0));//地址的大小--4
	printf("%d\n", sizeof(*arr));//1
	printf("%d\n", sizeof(arr[1]));//1
	printf("%d\n", sizeof(&arr));//地址的大小---4
	printf("%d\n", sizeof(&arr + 1));//4
	printf("%d\n", sizeof(&arr[0] + 1));//4
	
	printf("%d\n", strlen(arr));//随机值(strlen函数遇见‘\0’停止计数)
	printf("%d\n", strlen(arr + 0));//随机值
	//printf("%d\n", strlen(*arr));//错误
	//printf("%d\n", strlen(arr[1]));//错误
	printf("%d\n", strlen(&arr));//随机值
	printf("%d\n", strlen(&arr + 1));//随机值-6
	printf("%d\n", strlen(&arr[0] + 1));//随机值-1
	
	char arr[] = "abcdef";//[a b c d e f \0]
	printf("%d\n", sizeof(arr));//7
	printf("%d\n", sizeof(arr + 0));//4
	printf("%d\n", sizeof(*arr));//1
	printf("%d\n", sizeof(arr[1]));//1
	printf("%d\n", sizeof(&arr));//4
	printf("%d\n", sizeof(&arr + 1));//4
	printf("%d\n", sizeof(&arr[0] + 1));//4
	
	printf("%d\n", strlen(arr));//6
	printf("%d\n", strlen(arr + 0));//6
	//printf("%d\n", strlen(*arr));//错误
	//printf("%d\n", strlen(arr[1]));//错误
	printf("%d\n", strlen(&arr));//6
	printf("%d\n", strlen(&arr + 1));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//5
	
	char* p = "abcdef";
	printf("%d\n", sizeof(p));//4
	printf("%d\n", sizeof(p + 1));//4
	printf("%d\n", sizeof(*p));//1
	printf("%d\n", sizeof(p[0]));//1
	printf("%d\n", sizeof(&p));//4
	printf("%d\n", sizeof(&p + 1));//4
	printf("%d\n", sizeof(&p[0] + 1));//4
	
	printf("%d\n", strlen(p));//6
	printf("%d\n", strlen(p + 1));//5
	//printf("%d\n", strlen(*p));//错误
	//printf("%d\n", strlen(p[0]));//错误
	printf("%d\n", strlen(&p));//随机数
	printf("%d\n", strlen(&p + 1));//随机值
	printf("%d\n", strlen(&p[0] + 1));//5
	
    //二维数组
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//48=3*4*sizeof(int)
	printf("%d\n", sizeof(a[0][0]));//第一行第一个元素的大小----4
	printf("%d\n", sizeof(a[0]));//16
	printf("%d\n", sizeof(a[0] + 1));//4----a[0]作为数组名并没有单独放在sizeof内部
	                                //也没有取地址,所以a[0]表示第一行第一个元素的地址
	                                //a[0]+1表示第一行第二个元素的地址
	printf("%d\n", sizeof(*(a[0] + 1)));//4---*(a[0] + 1)表示第一行第二个元素
	printf("%d\n", sizeof(a + 1));//4---第二行的地址的大小
	printf("%d\n", sizeof(*(a + 1)));//16----第二行的元素的大小
	printf("%d\n", sizeof(&a[0] + 1));//4
	printf("%d\n", sizeof(*(&a[0] + 1)));//16
	printf("%d\n", sizeof(*a));//16--第一行的大小
	printf("%d\n", sizeof(a[3]));//16---第四行的大小(不存在,也能通过类型计算)
}

2.

int main()
{
 int a[5] = { 1, 2, 3, 4, 5 };
 int *ptr = (int *)(&a + 1);
 printf( "%d,%d", *(a + 1), *(ptr - 1));
 return 0;
}
//程序的结果是什么?

2 ,5

a是数组首元素的地址,a+1指向了第二个元素

&a是整个数组的地址,ptr即&a+1跳过了整个数组,指向了最后一个元素后的位置,ptr-1即指向了最后一个元素

3.

//结构体的大小是20个字节
struct Test
{
 int Num;
 char *pcName;
 short sDate;
 char cha[2];
 short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
 printf("%p\n", p + 0x1);
 printf("%p\n", (unsigned long)p + 0x1);
 printf("%p\n", (unsigned int*)p + 0x1);
 return 0;
}

0x00100014 0x00100001 0x00100004(0x表示十六进制)
第一个printf是指针+1,跳过的是一整个结构体的大小,这个结构体的大小是20个字节,在十六进制中是“14”,即0x00100014。
第二个printf是将结构体指针p转化为无符号整型的p,整型+1的结果就是在原本的值的基础上+1,所以就是0x00100001。
第三个printf是将结构体指针p转换成为无符号整型指针,既然是指针,跳过的就是整型指针类型,那就是跳过4个字节,答案就是0x00100004。

%p打印的是地址,32位机器上是占4个字节的,也就是0x00 00 00 00八位。 

4.

//小端
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;
}

4 2000000

&a是取出的一整个数组的地址,而+1以后是跳过这一整个数组往后找下一个数组,那后面打印的是ptr[-1]相当于ptr1-1,ptr1-1是往后一个整型指针类型的大小,那么指向的就是4

a是首元素的地址,但解引用成(int),所以a就是一个简单的整型,不是指针,所以单纯的+1就是单纯的跳过一个字节,因为4+1=5(跳过的是1个字节),指针4+1=8(跳过的是4个字节),那所以(int)a+1指向的就是00这个字节,而当(int)a+1整个强制类型转换成为(int*),整型指针占4个字节,那就是从(int)a+1这个指向的字节位置往后找4个字节即可,那就是00 00 00 02,而我们题目给定的条件是小端存放,且在x86的情况下,那么我们进行拿出来显示的时候是02000000,所以%p结果就是0x02000000,而这道题目要求的是%x,也就是十六进制,则前导的0要删掉。
 

5.

#include <stdio.h>
int main()
{
 int a[3][2] = { (0, 1), (2, 3), (4, 5) };
 int *p;
 p = a[0];
 printf( "%d", p[0]);
 return 0;
}

1

(,),逗号表达式返回的是后面的值,所以值为1,3,5,0,0,0。我们知道二维数组的值那就好办了,a[0]就是二维数组的首行数组名,那也就是p这个指针指向的是a这个二维数组首行的地址,也就是两个元素,而p[0]又是*(p+0)==*p,那也就是1了。

6.

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

0xFFFFFFFC,-4
int(*)[5]是一组中有五个元素的,而p的类型是int(*)[4],是一组中有4个元素的,这两个类型不匹配,直接将a赋给p了,则p现在是将a的内存空间进行划分,四个元素四个元素划分一个,所以p[4][2]-a[4][2]低地址减高地址,那就是-4了,然而前面要的是%p,那是个地址,我们知道在计算机内存中数字是以二进制的补码存储的,那这就很简单了,地址又不看补码的,直接换算成地址,那就是0xFFFFFFFC了。

7.

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

10 5

&aa取的是整个数组的地址,那+1是跳过整个二维数组,那就是指向10的末尾,那-1是指向的是10,再解引用就拿出来的结果为10

aa是首个数组的地址,+1是跳过首个数组到第二个数组的头,但此时也是取的是第二个数组,但是进行强制类型转换了,所以ptr2指针-1是跳过一个元素,所以显示的是5。

8.

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

at
char* a[]指向的是后面三个字符串的首元素,而char** pa=a,所以pa指向的是字符指针a的首元素,这个关系我们清楚了以后,看一看pa++的含义,我们此时想了,char** pa的含义是:char* *pa,这个意思是对pa进行加一的操作,是跳过的一个char*元素,所以指向的是’a’,进行解引用打印字符串打印的就是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);
 return 0;
}

POINT ER ST EW

++cpp为cpp=cpp+1,cpp指向c+3,cpp+1指向c+2,解引用即为POINT

cpp再次自增则此时cpp指向c+1,第一次解引用后自减指向“ENTER”的首元素,+3指向‘E'解引用即为ER

cpp[-2]为c+3,指向“FIRST”的首元素,+3指向’S‘解引用即为ST

cpp[-1][-1]指向“NEW”的首元素,+1指向’E‘解引用即为ST

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值