指针笔试题

目录

一、回调函数

二、笔试题

2.1. 设有定义:char p[]={'1','2','3'},*q=p;

2.2.https://blog.csdn.net/qq_30460949/article/details/89293098的相关问题: 

 2.3 一维数组的字节数

 2.4 字符数组

2.4.2 对于如下数组:char arr[] = "abcdef";

 2.4.3 对于char *p = "abcdef";

 2.5 二维数组

一、回调函数

        回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由

#include <stdio.h>
//qosrt函数的使用者得实现一个比较函数
int int_cmp(const void * p1, const void * p2)
{
return (*( int *)p1 - *(int *) p2);
}
int main()
{
int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
int i = 0;
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
{
printf( "%d ", arr[i]);
}
printf("\n");
return 0;
}

二、笔试题

2.1. 设有定义:char p[]={'1','2','3'},*q=p;

以下不能计算出一个char型数据所占字节数的表达式是
A)sizeof(p) B)sizeof(char) C)sizeof(*q) D)sizeof(p[0])

答案是A。A计算出来的是P这个数组的全部长度,也就是包含了3个char的长度,原因很简单数组名就是数组的首地址,也就是说,P是指向整个数组的指针,对它计算当然得到的是整个数组的长度,后面的几个答案,都取出了地址上的值,比如*q是第一个值,p[0]也是,sizeof(char)这个更不用说了,直接就是计算char在计算机里的长度。所以答案是A

2.2.https://blog.csdn.net/qq_30460949/article/details/89293098的相关问题: 

char* (*p)():定义一个函数指针,所指向函数返回值为字符指针。

char* p():声明一个函数返回值为一个指向字符(串)的指针。

char*p[]:首先是一个数组,每个元素为一个指向字符(串)的指针。

例如char* p[3] = { "111", "222", "333"}:“[“ 的优先级高于 ”*”  意味着p是一个有3个元素的数组元素的类型是 char*。或者可以理解将p和[3]在一起,则p[3]是个数组,p存放的是数组中首个元素的地址,数组里存放的 char*类型的数据,char* 类型即是指针类型,也就是里面是指针,即:某个变量的地址。

char (*p)[]:是一个指针,指向一个字符数组。

例如char (*p)[10]:“(“的优先级最高, 意味着p是一个指针,指向一个有10个char元素的数组。或者可以将 (*p)看成一个整体,然后(*p)存放的是char[3]数组中首个元素的地址,p存放的是(*p)的地址,即:数组的地址。

char* p和char p[]赋值时的区别:

1)、看这个赋值语句char *s="abc":

       右边,是"abc",是个字符串常量,存在于内存某处,字符串常量所在内存是只读的。

       左边,字符指针s,赋值的时候,把地址偏移到"abc"所在的地址,存放到指针变量s中。

        程序员能控制的内存是该指针变量所指向的这四个字节内存,仅能改变该指针的指向,

2)、再看这个赋值char p[]="abccd"语句:

        右边,和上面类似,是"abccd",也是个字符串常量,存在于内存某处,编译器分配的(赋值之后,程序员不知道这个常量存在何处,由于没有用指针指向这块内存,这和上面不同)。该字符串常量所在内存也是只读的。

         左边,字符数组p,赋值的时候,把地址所指内存中的内容,复制到从字符数组p开始指向的内存中,每复制一个字符都会开辟一个字节(char型变量占1字节)内存来存放这个字符(这也是实现了数组元素个数的动态存储)。程序员可以完全控制从字符数组p开始的这部分到复制结束存放这些字符的内存,可读可写,因此在这些内存写不会出错。

 2.3 一维数组的字节数

数组名的意义:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));

 首先:不难发现是小端字节存储,且int 在64位下占4个字节。

 &a :a的地址是0x005ff914,&a+1的地址是0x005ff924,刚好跳过了整个数组。

  

可以通过调试,了解他们的类型: 

&a -> int(*)[4]类型

&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。下图的错误:

 结果:

        X86:32位系统,是指操作系统一次性可以处理的位数是32。x86指的是一种cpu的架构,x86架构的特点是cpu的寄存器是32位的。
        X64:也可写作X86-64,64位系统,指操作系统一次性可以处理的位数是64。x64架构的特点是cpu的寄存器是64位的。
不同位数OS下的变量类型的长度如下:

32位平台(x86)

char         1个字节8位

short        2个字节16位

int            4个字节32位

long         4个字节

long long 8个字节

指针         4个字节

64位平台 (x64)

char         1个字节

short        2个字节

int            4个字节

long         8个字节(区别)

long long 8个字节

指针        8个字节(区别)
原文链接:https://blog.csdn.net/u014689845/article/details/103526652

在64位下:

 在32位下:

 2.4 字符数组

2.4.1 对于char arr[] = { 'a','b','c','d','e','f' };

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));
	//arr单独在sizeof里面,代表整个数组,6*1 = 6
	printf("%d\n", sizeof(arr + 0));
	//arr+0代表首元素的地址,4/8
	printf("%d\n", sizeof(*arr));
	//首元素,1
	printf("%d\n", sizeof(arr[1]));
	//第二个元素,1
	printf("%d\n", sizeof(&arr));
	//数组的地址,4/8
	printf("%d\n", sizeof(&arr + 1));
	//跳过数组,还是地址,4/8
	printf("%d\n", sizeof(&arr[0] + 1));
	//首元素的地址+1,第二个元素的地址,4/8

	return 0;
}

在64位下: 

sizeof只关注占用空间的大小,单位是字节
sizeof不关注类型
sizeof是操作符
strlen关注的字符串中\0的为止,计算的是\0之前出现了多少个字符
strlen指针对字符串
strlen是库函数

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));//arr是首元素的地址,但是arr数组中没有\0,计算的时候就不知道什么时候停止,结果是:随机值
	printf("%d\n", strlen(arr + 0));//arr是首元素的地址,arr+0还是首元素的地址,结果是:随机值
	
	printf("%d\n", strlen(*arr)); //error,strlen需要的是一个地址,从这个地址开始向后找字符,直到\0,统计字符的个数。
	//但是*arr是数组的首元素,也就是'a',这时传给strlen的就是'a'的ascii码值97,strlen函数会把97作为起始地址,统计字符串,会形成内存访问冲突
	
	printf("%d\n", strlen(arr[1]));//error 和上一个一样,内存访问冲突

	printf("%d\n", strlen(&arr));//&arr是arr数组的地址,虽然类型和strlen的参数类型有所差异,但是传参过去后,还是从第一个字符的
	//位置向后数字符,结果还是随机值。

	printf("%d\n", strlen(&arr + 1));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//随机值

	return 0;
}

2.4.2 对于如下数组:char arr[] = "abcdef";

int main()
{
	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));
	//arr单独出现在sizeof内,代表数组,1*7=7,算上\0
	printf("%d\n", sizeof(arr + 0));
	//代表首元素地址,4/8
	printf("%d\n", sizeof(*arr));
	//代表首元素1
	printf("%d\n", sizeof(arr[1]));
	//代表第二个元素1
	printf("%d\n", sizeof(&arr));
	//数组的地址4/8
	printf("%d\n", sizeof(&arr + 1));
	//跳过数组的地址4/8
	printf("%d\n", sizeof(&arr[0] + 1));
	//第一个元素的地址4/8
	/*printf("%d\n", strlen(arr));
	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));
	printf("%d\n", strlen(&arr[0] + 1));*/
	return 0;
}

int main()
{
	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));//有\0,能找打,结果是6
	printf("%d\n", strlen(arr + 0));//首元素的地址,6
	printf("%d\n", strlen(*arr));//同下
	printf("%d\n", strlen(arr[1]));//表示的是第一个元素‘b’,strlen需要的是地址,从一个地址向后找\0,统计个数,
	//‘b’的ascii码值是98,strlen就会从98看做事首地址向后找\0,会形成内存访问冲突
	printf("%d\n", strlen(&arr));
	//数组的地址,但还是从数组的首元素向后找\0,6
	printf("%d\n", strlen(&arr + 1));
	//跳过数组的地址,随机值
	printf("%d\n", strlen(&arr[0] + 1));
	//第一个元素的地址,5,arr[0]相当于*(arr+0)相当于*arr,相当于‘a’,取得是首元素的地址
	
	return 0;
}

  对于:printf("%d\n", strlen(*arr));

 2.4.3 对于char *p = "abcdef";

char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
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));

 在64位下:是地址就肯定是4/8,因为类型是char*

 

 2.5 二维数组

int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));

 

 数组名的意义:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。

 

int main()
{
	int a[3][4] = { 0 };

	printf("%d\n", sizeof(a));
	//a数组名,代表整个数组,3*4*4=48

	printf("%d\n", sizeof(a[0][0]));//4

	printf("%d\n", sizeof(*(a + 0)));//16
	//a+0相当于a[0]得到的是第一行的地址,*a[0]得到的是第一行的元素4*4=16

	printf("%d\n", sizeof(*(*(a + 0) + 0)));
	//4,相当于a[0][0]->*(a[0]+0)//得到的是第一行第一列的元素

	printf("%d\n", sizeof(a[0]));
	//a[0]表示第一行的数组名,a[0]作为数组名单独放在sizeof内部,计算的是第一行的大小4*4=16

	printf("%d\n", sizeof(a[0] + 1));//4/8
	//a[0]是第一行第一个元素的地址
	//a[0] + 1,就是第一行第2个元素的地址。

	printf("%d\n", sizeof(*(a[0] + 1)));//4
	//得到的是第一行第二个元素

	printf("%d\n", sizeof(a + 1));//4/8
	//a是二维数组的数组名,并没有取地址,也没有单独的放在sizeof(内部),
	//所以a就表示二维数组首元素地址,即:第一行的地址。
	//a + 1就是二维数组第二行的地址,

	printf("%d\n", sizeof(*(a + 1)));//16
	//*(a+1)得到第二行的元素,4*4=16

	printf("%d\n", sizeof(&a[0] + 1));//4/8
	//a[0]是第一行的数组名,&a[0]取出的就是第一行的地址
	//&a[0] + 1 就是第二行的地址

	printf("%d\n", sizeof(*(&a[0] + 1)));//16
	//&a[0]等价于a
	//&a[0]+1就是第二行的地址
	//*(&a[0] + 1)就是第二行 所以计算的是第二行的大小

	printf("%d\n", sizeof(*a));//16
	//*a > *(a+0) -> a[0] , 代表第一行地址,a[0]单独放在sizeof里,计算的是第一行的总大小

	printf("%d\n", sizeof(a[3]));//16
	//a[3]代表的是第三行,单独放在sizeof里,计算第三行的总大小

	printf("%d\n", sizeof(a + 2));//4
	//代表的是第一行的地址+2得到第三行的地址
	
	printf("%d\n", sizeof(a[0] + 3));//4
	//代表的是第一行第三个元素的地址
	return 0;
}

 

 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值