C语言--指针和数组面试题的解析

一维数组

int a[] = { 1,2,3,4 };

  • printf("%d\n", sizeof(a)); //数组a的字节大小:16
  • printf("%d\n", sizeof(a + 0));//数组首元素地址a[0]的地址的大小:4/8,x86占4个字节,x64占八个字节
  • printf("%d\n", sizeof(*a)); //a==(a+0),a[0]的字节大小:4
  • printf("%d\n", sizeof(a + 1));//数组首元素的下一个元素(即a[1]地址所占的字节长度:)4/8
  • printf("%d\n", sizeof(a[1])); //元素a[1]所占字节的大小 :4
  • printf("%d\n", sizeof(&a)); //数组a的地址所占的字节大小:4/8
  • printf("%d\n", sizeof(*&a)); //&a是整个数组的地址,*解引用得到的是整个数组的元素,所以真个数组的大小占16个字节
  • printf("%d\n", sizeof(&a + 1)); //&a表示的是整个数组地址的大小,+1表示指向数组后面的地址,所占字节为:4/8
  • printf("%d\n", sizeof(&a[0])); //&a[0]表示数组的第一个元素的地址所占的字节:4/8
  • printf("%d\n", sizeof(&a[0] + 1)); //&a[0]+1表示数组中a[1]的地址所占的字节:4/8
#include<stdio.h>
int main() {
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));    //数组a的字节大小:16
	printf("%d\n", sizeof(a + 0));//数组首元素地址a[0]的地址的大小:4/8,x86占4个字节,x64占八个字节
	printf("%d\n", sizeof(*a));   //*a==*(a+0),a[0]的字节大小:4
	printf("%d\n", sizeof(a + 1));//数组首元素的下一个元素(即a[1]地址所占的字节长度:)4/8
	printf("%d\n", sizeof(a[1])); //元素a[1]所占字节的大小 :4
	printf("%d\n", sizeof(&a));	  //数组a的地址所占的字节大小:4/8
	printf("%d\n", sizeof(*&a));  //&a是整个数组的地址,*解引用得到的是整个数组的元素,所以真个数组的大小占16个字节
	printf("%d\n", sizeof(&a + 1));     //&a表示的是整个数组地址的大小,+1表示指向数组后面的地址,所占字节为:4/8
	printf("%d\n", sizeof(&a[0]));		//&a[0]表示数组的第一个元素的地址所占的字节:4/8
	printf("%d\n", sizeof(&a[0] + 1));	//&a[0]+1表示数组中a[1]的地址所占的字节:4/8
	

	return 0;
}

字符数组

char arr[]={‘a’,‘b’,‘c’,‘d’,‘e’,’'f};
在内存中显示如下:
1

  • printf("%d\n", sizeof(arr)); //显示数组的所占的大小:6
  • printf("%d\n", sizeof(arr + 0)); //arr[0]所在地址所占字节的大小:4/8
  • printf("%d\n", sizeof(*arr)); //arr==(arr+0)显示数组的第一个元素的所占字节的大小:1
  • printf("%d\n", sizeof(arr[1])); //数组中第二个元素所占字节的大小:1
  • printf("%d\n", sizeof(&arr)); //数组arr的地址所占的字节:4/8
  • printf("%d\n", sizeof(&arr + 1)); //数组arr的地址后面的地址所占的字节:4/8
  • printf("%d\n", sizeof(&arr[0] + 1));//数组元素arr[1]的地址所占的字节元素:4/8
  • printf("%d\n", strlen(arr)); //随机值 由于数组后面不是以’\0’为结尾,strlen直到’\0’才计数结束,所以产生随机值
  • printf("%d\n", strlen(arr + 0)); //从arr[0]开始计数,也是产生的随机值
  • printf("%d\n", strlen(*arr)); //arr==(arr+0)==arr[0]=‘a’,ascii 码为:97 会产生报错
  • printf("%d\n", strlen(arr[1])); //arr[1]=‘b’,ascii 码为:98 会产生报错
  • printf("%d\n", strlen(&arr)); //随机值
  • printf("%d\n", strlen(&arr + 1)); //随机值
  • printf("%d\n", strlen(&arr[0] + 1)); //随机值
#include<stdio.h>
#include<string.h>
int main() {
	


char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));        //显示数组的所占的大小:6
	printf("%d\n", sizeof(arr + 0));    //arr[0]所在地址所占字节的大小:4/8
	printf("%d\n", sizeof(*arr));       //*arr==*(arr+0)显示数组的第一个元素的所占字节的大小:1
	printf("%d\n", sizeof(arr[1]));     //数组中第二个元素所占字节的大小:1
	printf("%d\n", sizeof(&arr));       //数组arr的地址所占的字节:4/8
	printf("%d\n", sizeof(&arr + 1));   //数组arr的地址后面的地址所占的字节:4/8
	printf("%d\n", sizeof(&arr[0] + 1));//数组元素arr[1]的地址所占的字节元素:4/8
	printf("%d\n", strlen(arr));        //随机值 由于数组后面不是以'\0'为结尾,strlen直到'\0'才计数结束,所以产生随机值
	printf("%d\n", strlen(arr + 0));    //从arr[0]开始计数,也是产生的随机值
	//	printf("%d\n", strlen(*arr));		//*arr==*(arr+0)==arr[0]='a',ascii 码为:97 会产生报错
	//	printf("%d\n", strlen(arr[1]));		//arr[1]='b',ascii 码为:98 会产生报错
	printf("%d\n", strlen(&arr));		//随机值
	printf("%d\n", strlen(&arr + 1));	//随机值
	printf("%d\n", strlen(&arr[0] + 1)); //随机值


	return 0;
}

字符串数组

char arr[]={“abcdef”};

2

  • printf("%d\n", sizeof§);//p表示的是指针变量 4/8
  • printf("%d\n", sizeof(p + 1));//p+1表示字符b的地址,所占字节:4/8
  • printf("%d\n", sizeof(*p)); //p==(p+0)表示字符a,字符所占字节为:1
  • printf("%d\n", sizeof(p[0]));//p[0]==*(p+0),表示字符a,所占字节为:1
  • printf("%d\n", sizeof(&p));//表示指向p的指针的地址的指针的地址,所占字节为:4/8
  • printf("%d\n", sizeof(&p + 1));//指向地址:4/8
  • printf("%d\n", sizeof(&p[0] + 1));//字符b的地址指向的所占的字节:4/8;
  • printf("%d\n", strlen§); //字符串的字符为6
  • printf("%d\n", strlen(p + 1));//从b开始,字符串的长度为5
  • printf("%d\n", strlen(*p));//*p表示’a’,产生错误
  • 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 &p[0]==*&(p+0)=p 所以长度为5
#include<stdio.h>
int main() {

	const char *p = "abcdef";
	printf("%d\n", sizeof(p));//p表示的是指针变量 4/8
	printf("%d\n", sizeof(p + 1));//p+1表示字符b的地址,所占字节:4/8
	printf("%d\n", sizeof(*p)); //*p==*(p+0)表示字符a,字符所占字节为:1
	printf("%d\n", sizeof(p[0]));//p[0]==*(p+0),表示字符a,所占字节为:1
	printf("%d\n", sizeof(&p));//表示指向p的指针的地址的指针的地址,所占字节为:4/8
	printf("%d\n", sizeof(&p + 1));//指向地址:4/8
	printf("%d\n", sizeof(&p[0] + 1));//字符b的地址指向的所占的字节:4/8;
	

	printf("%d\n", strlen(p)); //字符串的字符为6
	printf("%d\n", strlen(p + 1));//从b开始,字符串的长度为5
	printf("%d\n", strlen(*p));//*p表示'a',产生错误
	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 &p[0]==*&(p+0)=p	所以长度为5
	return 0;

}

二维数组

  • printf("%d\n", sizeof(a)); //表示整个数组所占字节的大小:48
  • printf("%d\n", sizeof(a[0][0])); //首元素的大小所占的字节的大小:4
  • printf("%d\n", sizeof(a[0])); //首行元素所占字节的大小:16
  • printf("%d\n", sizeof(a[0] + 1)); //第二行元素所占字节的大小:16
  • printf("%d\n", sizeof(*(a[0] + 1))); //表示第一行第二个元素的所占字节的大小:4
  • printf("%d\n", sizeof(a + 1));//数组名a,并没有单独放在sizeof内部,也没&,所以表示首元素(第一行)的地址,a+1就是第二行的地址,(把每一行看成一个元素)4/8
  • printf("%d\n", sizeof(*(a + 1)));//表示第二行元素所占的字节的大小:16
  • printf("%d\n", sizeof(&a[0] + 1));//第二行地址所占的字节的大小:4/8
  • printf("%d\n", sizeof(*(&a[0] + 1)));//第二行元素所占字节的大小:16
  • printf("%d\n", sizeof(*a));//a表示首元素,a==(a+0)==a[0],表示第一行元素所占字节的大小:16
#include<stdio.h>
int main() {

	int a[3][4] = { 0 }; 
	printf("%d\n", sizeof(a));  //表示整个数组所占字节的大小:48
	printf("%d\n", sizeof(a[0][0])); //首元素的大小所占的字节的大小:4
	printf("%d\n", sizeof(a[0])); //首行元素所占字节的大小:16
	printf("%d\n", sizeof(a[0] + 1)); //第二行元素所占字节的大小:16
	printf("%d\n", sizeof(*(a[0] + 1))); //表示第一行第二个元素的所占字节的大小:4
	printf("%d\n", sizeof(a + 1));//数组名a,并没有单独放在sizeof内部,也没&,所以表示首元素(第一行)的地址,a+1就是第二行的地址,(把每一行看成一个元素)4/8
	printf("%d\n", sizeof(*(a + 1)));//表示第二行元素所占的字节的大小:16
	printf("%d\n", sizeof(&a[0] + 1));//第二行地址所占的字节的大小:4/8
	printf("%d\n", sizeof(*(&a[0] + 1)));//第二行元素所占字节的大小:16
	printf("%d\n", sizeof(*a));//a表示首元素,*a==*(a+0)==a[0],表示第一行元素所占字节的大小:16
	
	return 0;

}

常见的面试题

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

1
根据上述的内存空间图可以看出:*(a+1)=a[1], *(ptr-1)=a[4];
所以打印的结果为:2 5

#include<stdio.h>
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;
}

这段代码还是比较有难度的,我们可以进行画图进行更容易的理解:(注意:这里的箭头我省略了,因为自己画图实在太难看。。。)这里是刚刚初始时各级指针的指向。

1
当代码执行打印printf("%s\n", **++cpp) 时: cp先自增再使用,所以现在的指针指向为:
2
所以此时此举打印的内容为:POINT

当执行第二句打印函数的时候:**printf("%s\n", ++cpp + 3); 我们继续画图方便理解:
可知cpp首先再自增,然后解引用,事得cp再自减,其次再解引用,让原来的c的原有值再+3:画图得到:

3
所以此时打印的字符串的结果是:ER。

继续分析下一句打印的内容:printf("%s\n", cpp[-2] + 3);
我们可以看出 cpp[-2]==
(cpp-2),此时指针回退两步,(注意:此时的cpp没有发生自增或自减,所以cpp的值没有发生改变),解引用后,使cp中的内容在原来的基础上+3,画图可得:

3
此时打印的字符串为:ST.

终于快要画完图了 哈哈哈,斗志昂扬的分析最后一个打印的函数:printf("%s\n", cpp[-1][-1] + 1);

cpp[-1][-1]=*( *(cpp-1)-1),我们上个打印函数的时候提到,cpp在自增自减的时候之才能发生改变,所以cpp指针依旧指向cp的第三块内存地址:
在这里插入图片描述

可知打印的字符串的结果为:EW

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

同样,我们根据画内存空间的方式来理解此段程序:

初始时,内存图的结构如下:
在这里插入图片描述

运行pa++后:
在这里插入图片描述

所以*pa的打印的字符串为:at

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

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

在这里插入图片描述

而指针-指针等于两个地址之间的元素,所以当打印:&p[4][2] - &a[4][2]的整形的时候:值为:-4
而打印地址的形式的时候:-4的原码为:1000 0000 0000 0000 0000 0000 0100
反码为:1111 1111 1111 1111 1111 1111 1111 1011
补码为:1111 1111 1111 1111 1111 1111 1111 1100
所以打印的地址形式为:FF FF FF FC

#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

struct Test
{
 int Num;
 char *pcName;
 short sDate;
 char cha[2];
 short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
 printf("%p\n", p + 0x1);
 printf("%p\n", (unsigned long)p + 0x1);
 printf("%p\n", (unsigned int*)p + 0x1);
 return 0;
}

结构体指针大小为20个字节,p是一个指向结构体的指针,p加1跳过二十个字节,所以 p + (0x1) =0x10014 。第二个是把结构体指针强制类型转换为(unsigned long)的数,对它加1,就直接给这个数加1,结果为0x100001。第三个是把结构体指针强制类型转换为(unsigned int*)类型,对它加1,偏移4个字节,结果为0x100004

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛应用于系统编程和嵌入式开发的高级编程语言。函数指针C语言中的一个重要概念,它可以指向函数,并且可以通过函数指针来调用函数。快速排序算法是一种常用的排序算法,它的核心思想是通过分治的策略将一个大问题分解为多个小问题,并通过递归的方式解决这些小问题。 下面是C语言中使用函数指针实现快速排序算法的示例代码: ```c #include <stdio.h> // 交换两个元素的值 void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } // 快速排序的分区函数 int partition(int arr[], int low, int high) { int pivot = arr[high]; // 选取最后一个元素作为基准 int i = (low - 1); // 定义一个指针,用于指向小于基准的元素 for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return (i + 1); } // 快速排序函数 void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); // 将数组分区,并获取分区点的位置 quickSort(arr, low, pi - 1); // 对分区点左边的子数组进行快速排序 quickSort(arr, pi + 1, high); // 对分区点右边的子数组进行快速排序 } } // 打印数组元素 void printArray(int arr[], int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); } int main() { int arr[] = {10, 7, 8, 9, 1, 5}; int n = sizeof(arr) / sizeof(arr[0]); printf("原始数组:"); printArray(arr, n); quickSort(arr, 0, n - 1); printf("排序后的数组:"); printArray(arr, n); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值