指针和数组面试题解析

数组名是首元素的地址,但是有两个例外
1.sizeof(首组名) - 数组名表示整个数组
2.&数组名 - 数组名表示整个数组
除了这两个之外,其他都是表示首元素的地址

一维数组

整型数组

```c
int main()
{
    
    
	int a[] = {
    
     1, 2, 3, 4 };
	printf("%d\n",sizeof(a));//16 
	//sizeof(数组名) -计算的是数组总大小,单位是字节 4*4 = 16
	printf("%d\n",sizeof(a+0));//4  
	//这里是a+0,但不是数组名,是首元素地址,是地址大小就是4/8个字节
	printf("%d\n",sizeof(*a)); //4
	// 数组名表示首元素地址 *a就是首元素,sizeof(*a)就是4
	printf("%d\n",sizeof(a+1)); //4
	//a还是首元素地址+1跳过一个元素,就是第二个元素的地址,所以还是4/8  在32是4 在64就是8
	printf("%d\n",sizeof(a[1])); //4 
	//计算第二个元素的大小
	printf("%d\n",sizeof(&a));//4
	//&a  取出的是数组的地址,但是数组的地址也是地址,地址的大小就是4个或者8个字节 
	printf("%d\n",sizeof(*&a));//16
	// &a 是数组的地址,数组的地址解引用访问的是数组,sizeof计算的是数组的大小,单位是字节
	printf("%d\n",sizeof(&a+1));//4/8
	//&a是数组的地址,&a+1虽然地址跳过整个数组,但还是地址,所以是4/8个字节
	printf("%d\n",sizeof(&a[0]));//4/8
	//&a[0] 取出的是第一个元素的地址
	printf("%d\n",sizeof(&a[0]+1));//4/8
	//&a[0]+1 第二个元素的地址,还是地址 结果是:4/8
	return 0;
}

字符数组

char arr[] = { ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’ };

int main()
{
    
    
	char arr[] = {
    
     'a', 'b', 'c', 'd', 'e', 'f' };
	printf("%d\n", sizeof(arr));//6
	//sizeof计算的是数组大小 6个元素 每个元素是char 单位是字节
	printf("%d\n", sizeof(arr + 0));//4
	//这里arr也是首元素地址,所以还是4
	printf("%d\n", sizeof(*arr));//1
	//arr是首元素地址,解引用就是首元素 ,首元素大小1个字节
	printf("%d\n", sizeof(arr[1]));//1
	//这里算的是第二个字符的大小也是1
	printf("%d\n", sizeof(&arr));//4
	//这里取整个数组的地址,但还是地址,所以大小是4/8
	printf("%d\n", sizeof(&arr + 1));//4
	//这里整个数组的地址&arr+1,就是跳过整个数组,但还是地址地址大小是4/8个字节
	printf("%d\n", sizeof(&arr[0] + 1));//4
	//取出第一个元素的地址+1 那么就是第二个元素的地址

	//strlen是求字符串的长度,也就是在找\0 strlen要的是地址,不要传其他的
	//arr没有被sizeof(arr) &arr 之外就是首元素的地址
	printf("%d\n", strlen(arr));//随机值
	//这里的arr表示的是首元素的地址 strlen找不到\0所以就是随机值
	printf("%d\n", strlen(arr + 0));//随机值
	//这里的arr表示的是首元素的地址 strlen找不到\0所以就是随机值
	printf("%d\n", strlen(*arr));//非法访问 err
	//这里是字符'a' 字符a的Ascall值是97相当于把97传进去
	printf("%d\n", strlen(arr[1]));//非法访问 err
	//这里是字符'b' 字符b的Ascall值是98相当于把98传进去
	printf("%d\n", strlen(&arr));//随机值
	//这里也是随机值 因为找不到\0
	printf("%d\n", strlen(&arr + 1));//随机值
	//这里也是随机值,找不到\0
	printf("%d\n", strlen(&arr[0] + 1));//随机值
	//这里还是随机值,因为也找不到\0
	return 0;
}

字符数组

char arr[] = “abcdef”;

int main()
{
    
    
	char arr[] = "abcdef";
	永远记住strlen接收的是地址
	printf("%d\n", strlen(arr));//6
	/*
	首先这里把首元素地址传过去然后开始往后找\0找到\0停止,然后找到\0前面的6个字符
	\0不算内容 它只是字符串的结束标志
	*/
	printf("%d\n", strlen(arr + 0));//6
	/*
	这里的首元素地址+0还是首元素的地址所以从首元素开始数,找\0还是六个字符
	*/
	printf("%d\n", strlen(*arr));//无法计算 非法访问内存err
	printf("%d\n", strlen(arr[1]));//无法计算  非法访问内存err
	printf("%d\n", strlen(&arr));//6
	/*
	&arr是数组的地址,把这个地址交给strlen,strlen把这个地址依然当作起始位置开始数
	得到的结果依然还是6个
	strlen参数类型是 my_strlen(const char* str)
	&arr-取出的是数组的地址 -要用数组指针存起来,char(*p)[7] = &arr;
	这里把数组指针的地址传给传给参数位 char*str类型的地址 两个类型不兼容,会有警告,
	强行赋值没关系,不影响结果
	*/
	printf("%d\n", strlen(&arr + 1));//这里是随机值
	printf("%d\n", strlen(&arr[0] + 1));//5
	/*
	&arr[0]+1其实就是b的地址,从b开始数知道\0停止 \0不算,所以长度是5
	*/
	printf("%d\n", sizeof(arr));		
	//这里初始化arr的时候数组里面放的是 abcdef \0
	/*
	sizeof(arr)这个时候这里的数组名表示的是整个数组 7个元素 7*1 = 7
	sizeof关注的是所占空间的大小
	sizeof(arr)计算的是数组的大小单位是字节
	*/
	printf("%d\n", sizeof(arr+0));//4
	/*
	arr表示数组名首元素的地址,计算的是地址的大小 arr+0还是算地址,地址只有4/8
	*/
	printf("%d\n", sizeof(*arr));//1
	/*
	首元素地址被解引用那么就找到了首元素,数组每个元素都是一个字符,首元素也是一个字符
    *arr是首元素,sizeof(*arr)计算首元素的大小
    */
	printf("%d\n", sizeof(arr[1]));	//1
	/*
	计算第二个数组,大小当然也是1了 arr[1]是第二个元素,
	sizeof(arr[1])计算的是第二个元素的大小
	*/
	printf("%d\n", sizeof(&arr));//4/8
	/*
	&arr虽然是数组的地址,但也是地址,所以是4个字节或者是8个字节
	*/
	printf("%d\n", sizeof(&arr+1));	//4/8
	//这里还是地址,是地址那么就是4个或者是8个字节
	//&arr+1是跳过整个数组后的地址,但也是地址
	printf("%d\n", sizeof(&arr[0]+1));//4/8
	//这边还是地址,是地址sizeof大小就是4个字节或者8个字节
	return 0;
}

字符数组

char *p = “abcdef”;

int main()
{
    
    
	char *p = "abcdef";

	printf("%d\n", strlen(p));//1
	/*
	因为p里面存的是a的地址,从a开始数字符,找到\0一共是六个\0不算
	*/
	printf("%d\n", strlen(p + 1));//5
	/*
	a的地址加1 就是b的地址,所以就是5
	*/
	printf("%d\n", strlen(*p));//非法访问内存操作
	printf("%d\n", strlen(p[0]));//非法访问内存操作
	printf("%d\n", strlen(&p));//随机值
	/*
	这里的&p存放的是p的地址,所以无发预知
	*/
	printf("%d\n", strlen(&p + 1));//随机值
	/*
	这里的&p存放的是p的地址,所以无发预知
	*/
	printf("%d\n", strlen(&p[0] + 1));
	/*
	这里是拿出第一个元素地址+1,那就是第二个元素,从第二个元素开始找\0,一直找到\0
	找到\0就是5个元素
	*/

	这个意思是把常量字符串abcdef中的a的地址放到p这个指针变量里面去了
	printf("%d\n", sizeof(p));//4
	/*
	p是指针变量  计算指针变量p的大小 因为p里面存的是a的地址,所以是地址,4/8
	*/
	printf("%d\n", sizeof(p+1));//4
	/*
	p+1的到的是字符b的地址,地址就是大小4/8个字节
	*/
	printf("%d\n", sizeof(*p));//1
	/*
	*p就是字符串的第一个字符,就是字符a 
	*/
	printf("%d\n", sizeof(p[0]));//1
	//数组名就是首元素地址,
	//int arr[10]; arr[0] ==*(arr+0) p[0] ==*(p+0) =='a'
	printf("%d\n", sizeof(&p));//4
	/*
	取出p的地址,还是地址所以是4/8个字节
	*/
	printf("%d\n", sizeof(&p+1));//4/8
	/*
	这里&p+1它还是地址,所以算出结果是4个或者是8个字节
	*/
	printf("%d\n", sizeof(&p[0]+1));//1 
	/*
	p[0]是a &p[0]其实就是拿到了a的地址+1,就是到b sizeof(b)就是1
	*/
	/*return 0;
}*/

二维数组

int main()
{
    
    
	int a[3][4] = {
    
     0 };
	printf("%d\n", sizeof(a));//48
	/*
	数组名单独放在sizeof(a)计算的是数组总大小
	3*4*4 = 48
	*/
	printf("%d\n", sizeof(a[0][0]));//4
	/*
	sizeof(a[0][0]) 计算的是第一行的第一个元素所以大小是4
	*/
	printf("%d\n", sizeof(a[0]));//16
	/*
	a[0]相当于第一行作为一维数组的数组名,sizeof(arr[0])
	把数组名单独放在sizeof内计算的是,第一行的大小
	*/
	printf("%d\n", sizeof(a[0]+1));
	/*
	a[0]是第一行的数组名也就是第一行首元素的地址,第一行数组的首元素的地址
	所以a[0]+1 就是第一行第二个元素的地址,地址大小是4/8个字节
	*/
	printf("%d\n", sizeof(*(a[0]+1)));//4
	/*
	a[0+1]就是第一行第二个元素的地址对它进行解引用,就找到了第一行的第二个元素
	元素大小是int所以是4个字节
	*/
	printf("%d\n", sizeof(a+1));//4
	/*
	a是二维数组的数组名,没有sizeof(数组名),也没有&(数组名),所以a是首元素地址,
	而把二维数组看成一维数组时,二维数组的首元素是他的第一行,a就是第一行的地址
	a+1那么就是第二行的地址
	*/
	printf("%d\n", sizeof(*(a+1)));//16
	/*
	第二行的地址解引用,第二行是数组,数组大小4个元素每个元素4个字节,所以是16
	*/
	printf("%d\n", sizeof(&a[0]+1));//4
	/*
	 a[0]是第一行的数组名 取出第一行的地址,第一行的地址+1就是第二行的地址
	*/
	printf("%d\n", sizeof(*(&a[0] + 1)));//16
	/*
	第二行的大小4*4 = 16
	*/
	printf("%d\n", sizeof(*a));//16
	/*
	a是第一行的地址,解引用就是第一行,所以4*4=16
	a是首元素地址-第一行的地址,*a就是第一行,sizeof(*a)就是计算第一行的大小
	*/
	printf("%d\n", sizeof(a[3]));//
	/*
	sizeof是不会去访问的,不参与真实计算的,只是根据它的类型来计算大小
	a[3]是4个整型一维数组所以是16
	*/
	return 0;
}	

总结

数组名的意义:

1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
3.除此之外所有的数组名d都表示首元素的地址
strlen不能求整型数组的大小,他只能求字符数组的大小

指针笔试题

写代码有三种境界
1.看代码是代码
2.看代码是内存
3.看代码是代码

指针第一题

int main()
{
    
    
	int a[5] = {
    
     1, 2, 3, 4, 5 };
	int *ptr = (int*)(&a + 1);
	printf("%d,%d", *(a + 1), *(ptr - 1));//2 5
	/*
	&a+1是数组的地址。类型是数组指针类型 
	&a+1是指向5后面的地址,ptr是整型地址ptr-1向前移动一个整型
	*ptr解引用向前移动1个元素的那个整型 ,
	*/
	return 0;
}

指针第二题

struct Test
{
    
    
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p的值为 0x100000,如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
    
    
	p = (struct Text*)0x100000;
	/* 让这个整型0x100000强制类型转换成结构体类型 */
	printf("%p\n", p + 0x1);//0x00100014  
	/*
		0x1就是1 那么就是p+1
		p是结构体指针,跳过一个结构体,
		0x100000+20 = 0x100014
	*/
	printf("%p\n", (unsigned long)p + 0x1);//0x00100001
	/*
	这里将p转化成整数了 100000整数时 
	16进制的100000转化成整数就是1048576
	1048576 + 1 = 1048577
	1048577转化成16进制就是0x00100001
	整型类型加1就是直接加1 
	在100000的基础上增加了1 就是00100001
	*/
	printf("%p\n", (unsigned int*)p + 0x1);//0x00100004
	/*
	将p强制转换成无符号的指针 + 1那么就要跳过一个无符号整型4个字节
	100000 + 4 = 0x00100004
	*/
	return 0;
}

指针第三题

在这里插入图片描述

int main()
{
    
    
	int a[4] = {
    
     1, 2, 3, 4 };
	int *ptr1 = (int *)(&a + 1);
	/*
	数组的地址+1就是跳过整个数组指向4后面的那个地址
	然后将数组地址强制类型转换成整型指针
	ptr1指向4后面的地址 
	*/
	int *ptr2 = (int *)((int)a + 1);
	/*
	a是首元素地址,强制类型转换成整数,整数加1
	也就是相当于地址向后偏移一个字节
	*/
	printf("%x,%x", ptr1[-1], *ptr2);//4,    2000000
	/*
		ptr1[-1] = *(ptr+(-1)) =*(ptr-1)
		整型指针向前移动一个整型,也就是4的那个位置
		然后进行解引用结果就是4

		ptr2指向的位置解引用
		整型指针可以访问4个字节,所以从位置向后访问4个字节
		因为是小端存储的
		所以00 00 00 02拿出来就是02000000
	*/
	//%X是以16进制的形式打印
	return 0;
}

指针第四题

int main()
{
    
    	
	int a[3][2] = {
    
     (0,1), (2,3), (4,5) };	
	/*
		逗号表达式,只看逗号后面的数字
		所以就会是这样进行存储的
		1   3 
		5   0
		0   0
	*/
	int *p;
	p = a[0];
	/*
	a[0]是第一行的数组名,也就是第一行第一个元素的地址
	p[0] = *(p+0)
	*/
	printf("%d", p[0]);//1
	return 0;
}

指针第五题

在这里插入图片描述

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]);
	/*
		&a[4][2]就是取第五行第三个元素的地址
		a是首组名就是首元素的地址,二维数组就是第一行的地址
		a强行赋给p p还是指向首元素地址,指的是首行的地址
		p[4][2]就是   p[4] = *(p+4) 
		 p[4][2]	== *(*(p+4)+2) 
		 找到*(*(p+4)+2)所指向的位置
		*(p+4)先找到,然后解引用拿到4个元素 *(p+4)相当于数组名
		首元素地址 然后地址加2,往后移动二位,然后在解引用拿到的那个元素
		拿到了元素之后在进行& 然后进行指针减去指针的运算
		中间有4个元素,所以是-4因为是低地址减去高地址
		但是是以%d形式打印的确实打印-4
		但是以%p形式打印,所以会按照-4放在内存中补码的直接值
		-4  10000000 00000000 00000000 00000100 - 原码
		    11111111 11111111 11111111 11111011 - 反码
			11111111 11111111 11111111 11111100 -补码
		会直接打印补码,但是是按照10进制打印,所以
		fffffffc
	*/
	结果是:fffffffc   -4
	数组指针一个指向数组的指针对它加1的时候,它会向后偏移一个字符
	return 0;
}

指针第六题

在这里插入图片描述

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));
/*
&aa+1就是把整个二维数组向后跳过一个二维数组指针指向10的后面
aa首组名表示首元素的地址,因为是二维数组,所以首元素是第一行的地址
第一行的地址+1那么就是跳到第二行
*(aa+1)对aa+1进行解引用就相当于找到了第二行,那么它就相当于第二行的数组名
*(aa+1) ==aa[1] 表示第二行的数组名,第二行首元素的地址

ptr1-1 因为是整型指针,所以向左移动一个然后解引用找到数字10
ptr2-1 因为是首元素地址 - 1,所以向前移动一个然后再解引用,所以找到数字5
*/
	return 0;
}

为什么*(p+2) == arr[2]呢

int main()
{
    
    
	int arr[10] = {
    
     1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int *p = arr;
	*(p + 2);//arr[2] 这两个是一样拿到第三个元素
	//所以说*(p+2) == arr[2]
	return 0;
}

要作阿里巴巴面试题先看这个实例.

int main()
{
    
    
	char* p = "abcdef";
	/*这个意思是把常量字符串首字符地址a放到p里面去p里面存放的就是
	首字符的地址
	*/
	return 0;
}

阿里巴巴笔试题

在这里插入图片描述

int main()
{
    
    
	char *a[] = {
    
     "work", "at", "alibaba" };
	/*
	这里a是字符指针数组,存放的是地址,也就是  'w',   'a',  'a'的地址  
	a数组有三个元素,每个元素类型都是         char*   char*  char*
	*/
	char** pa = a; 
	/*
	char**pa意思是 pa指向的元素是char*类型的 *pa表示pa是指针 
	*/
	//int* p;   p+1意思就是跳过一个整型 *p说明p是指针,指向的类型是int
	pa++;
	/*pa++跳过一个char*类型的变量
	pa就指向了第二个char*类型的变量*/
	printf("%s\n", *pa);
	/*
	*pa那么就是第二个char*的内容,内容就是at里面 a的地址
	用%s来打印,那么就是以a的地址开始打印字符串那么打印的就是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);//point
	printf("%s\n", *--*++cpp + 3);//ER
	printf("%s\n", *cpp[-2] + 3);//ST
	printf("%s\n", cpp[-1][-1] + 1);//EW
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_52495715/article/details/120822048
今日推荐