C语言之指针进阶

C语言之指针进阶,第1张

大家好啊,因为上个星期生病的原因,没有及时更新,本期这就补上。
本期主要内容是深入解析指针,让大家能够进一步了解指针,希望对各位小伙伴有所帮助!

文章目录
  • 前言
  • 一、指针的基本概念
  • 二、字符指针
  • 三、指针数组
  • 四、数组指针
    • 小知识点——数组名与&数组名
    • 数组指针的使用
    • 小结
  • 五、 数组参数与指针参数
    • 1、一维数组传参
    • 补充知识点
    • 2、二维数组传参
    • 重要知识点
      • 1、void pri(int *p)
      • 2、void pri(int **p)
  • 六、函数指针
    • 1、概念
    • 2、代码
    • 补充
    • 3、两道例题
      • 例题1
      • 例题2
    • 4、计算器
  • 七、函数指针数组
    • 1、概念
    • 2、代码
    • 3、小例子
    • 4、转移表
  • 八、指向函数指针数组的指针
  • 九、回调函数
    • 1、概念
    • 2、qsort函数
      • A、冒泡排序优化
      • B、qsort函数(重点)
        • void*指针
        • qsort排序整型数据类型
        • qsort函数排序结构体数据类型
        • qsort实现冒泡函数
    • 小结
  • 十、指针数组笔试题+讲解
    • 第一组
    • 第二组
    • 第三组(陷阱多)
      • 补充知识点
    • 第四组
      • 补充知识点
    • 第五组
      • 补充知识点
    • 第六组
    • 第七组
    • 第八组
      • 补充知识点
    • 第九组
    • 第十组
    • 第十一组
    • 第十二组
    • 第十三组
    • 第十四组
    • 第十五组
    • 第十六组
  • 总结


前言
	C语言里面的指针可以说是非常重要的了,不管是以后学习数据结构还是什么其他内容,指针是重中之重, 
我本期除了会讲解指针的内容以外,还会有一套指针笔试题的讲解,话不多说,咋们进入正片。

一、指针的基本概念

1、指针其实本质上叫做指针变量,只不过我们为了更方便解读就
       口语化式的叫做指针

2、指针在32位平台占4个字节内存大小,在64位平台占8个字节
   内存大小


二、字符指针
字符指针的写法为:char *

常用的字符指针写法是:

char ch = 'a';
char* p = &ch;
*p = 'b';
printf("%c\n", ch);

还有一种写法是:

const char ch = "abcdef";
char* p = &ch;

可别小看这两行代码,里面蕴藏着许多内容:
1、这里可不是把abcdef全部放到指针p里面去了,而是把这个定义的字符串首元素a的地址赋给了指针p

当有了首元素地址之后,依次向后面打印就可以打印出整个字符串了;
2、这个字符指针的方法使用的时候,字符串“abcdef”是不可以被改变的:

这里大家可以看到’a’没有被改为‘w’,并且程序还挂了

这是为什么呢?
是因为,这里的“abcdef”是一个常量字符串,常量字符串是不可被修改的。p的权限变大了,因为p没有被修饰,所以p敢改这个字符串,但是程序会死掉,并且出现错误,所以我们才在前面加上一个const,来表明这里的常量字符串,不能被修改。

##  小例题
	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	char *p1 = "abcdef";
	char *p2 = "abcdef";
	if (arr1 == arr2)
		printf("yes\n");
	else
		printf("no\n");
	if (*p1 == *p2)
		printf("yes\n");
	else
		printf("no\n");

我直接公布答案了哦!

是不是有一部分小伙伴们做错了呢?
接下来我们来分析分析:

其实很好理解,就是:字符串相同,因为数组不同,所以两个字符串地址不同;而两个指针是指向同一个字符串的,所以两个指针地址相同


三、指针数组

指针数组的本质是一个数组,数组内部存放着指针
它的写法是:

	int* arr1[10];//整型指针数组(也叫一级整型指针数组)
	int* *arr2[10];//二级整型指针数组
	char* arr3[10];//一级字符指针数组
	char* *arr4[10];//二级字符指针数组

四、数组指针

数组指针本质上是一个指针,这个指针指向一个数组
结合上面的指针数组一起来看看:

	int arr[5] = {1,2,3,4,5};
	int(*p)[5] = &arr;

	int arr[10] = { 0 };
	int (*p)[10] = &arr;

	char* arr2[10] = { 0 };
	char* (*pa)[10] = &arr2;

以上就是数组指针与指针数组的区别,大家可千万不敢搞混了!!!


小知识点——数组名与&数组名

1、一般情况下数组名就是首元素地址
2、在sizeof和&arr的情况下,arr表示整个数组

大家看看两段代码:

大家可能会疑惑,接下来我为大家进行讲解:

大家只需要记住数组名代表整个数组的情况即可,后面我们有一组列题来专门讲这个数组名知识点的


数组指针的使用
#include
void pri1(int arr[3][5], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
void pri2(int(*p)[5], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			printf("%d ", p[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	pri1(arr, 3, 5);
	pri2(arr, 3, 5);
	return 0;
}

大家可以先看看这两段函数代码,我接下来为大家讲讲:

	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	printf("%p\n", arr);
	printf("%p\n", arr + 1);


可以看到二维数组加1,地址加了20个字节,也就是5个元素,正好就是二维数组的一整行元素

也就是说:

	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	pri1(arr, 3, 5);
	pri2(arr, 3, 5);


小结

我们来总结一下几个知识点

#include
int main()
{
	int a[5];
	int* b[5];
	int(*c)[5];
	int(*d[10])[5];
	return 0;
}


举个例子:


五、 数组参数与指针参数 1、一维数组传参

让我们看一组代码:

#include
void test(int arr[])
{}
void test(int arr[10])
{}
void test(int *arr)
{}
void test2(int *arr2[])
{}
void test2(int *arr2[20])
{}
void test2(int **arr2)
{}
int main()
{
	int arr[10] = { 0 };
	int* arr2[20] = { 0 };
	test(arr);
	test2(arr2);
	return 0;
}

大家知道答案吗?我直接公布答案了:

答案就是全部正确,大家可能知道1,2,4,5是怎么来的,那大家知道为什么3和4也是正确的吗?
请各位小伙伴们听我详细分解:


补充知识点
int *p1//一级指针
int **p2//二级指针
int***p3//三级指针
.
.
.
以此类推

二级指针是用来存放一级指针地址的;三级指针是用来存放二级指针地址的,也是以此类推


2、二维数组传参
#include
void test(int arr[3][5]])
{}
void test(int arr[][5]])
{}
void test(int arr[][])
{}
void test(int *arr)
{}
void test(int *arr[])
{}
void test(int* arr[5])
{}
void test(int(*arr)[5])
{}
void test(int **arr)
{}
int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}

大家知道这些函数接收参数是正确的吗?

为什么是以上的答案呢?我们一起来分析分析:

注意:上图内容很重要,小伙伴们一定要熟记于心!!!

重要知识点 1、void pri(int *p)

当函数参数是一个指针的时候,实参会是什么数据呢?

1、int arr[10]={0};
    pri(arr);
    可以是一个整型数组数组名
2、int a=10;
    pri(&a);
    可以是一个整型变量的地址
3、int *p=&a;
    pri§;
    可以是一个整型指针

只要是传参的值本质上是一个整型指针就行


2、void pri(int **p)

通过上面的例题我们就可以得知:只要传参本质是一个二级指针就行

1、int n = 10;
 int* p = &n; 	
 int** p1 = &p; 	
 pri(p1); 	
 pri(&p); 

2、指针数组的数组名也可以
    int*parr[10];
    pri(parr)


六、函数指针 1、概念

函数指针是一个指针,该指针指向一个函数,也就是指向函数的指针

2、代码
	int(*p1)[10];//这个是整型数组指针
	char(*p1)[10];//这个是字符数组指针
	int*(*p1)[10];//这个是一个指向存放10个整型指针数组的指针

	//重点来了
	
	int (*p2)(int ,int)//这个就是函数指针
	
#include
int add(int x, int y)
{
	return x + y;
}
void pri(int(*add)(int, int))
{
	int a = 5;
	int b = 5;
	int ret = add(a, b);
	printf("%d\n", ret);
}
int main()
{
	pri(add);
	return 0;
}


上面就是函数指针的基础用法。
我们来仔细分析:

以上就是函数指针的大体模板,只不过参数部分可以变得很复杂,小伙伴们一定要用心观察。

补充

函数名本质上并不是函数的地址。函数名可以当做函数地址来使用,这是因为发生了隐式转换,我们以后会讲到隐式转换我们可以拿着用。


3、两道例题 例题1
( * ( void ( * ) ( ) ) 0 )( )

哎呀!这是一个什么题啊,很多小伙伴直接懵逼了,别着急,我们一步步来:

例题2
	void ( * arr ( int , void ( * ) ( int ) ) ) ( int )

可能又有一部分人不理解这行代码了,我们继续:

以上代码有过多重复部分,我们可以进行简化:

	void ( * arr ( int , void ( * ) ( int ) ) ) ( int )
	typedef void(*p)(int);
	p arr(int, p);

这里我们用到了typedef重定义,可能有很多人问了,为什么不是【typedef void(*)(int) p】这样把p定义在最后呢?因为C语言的语法不是这样定义的。【typedef void(p)(int)】就相当于把【typedef void()(int)】重定义为了p。


4、计算器

函数指针有什么用呢?
接下来我们看看函数指针能怎么使用:
首先我们来看看最基础的一个计算器的实现:

#define _CRT_SECURE_NO_WARNINGS
#include
void menu()
{
	printf("*****0.exit*****\n");
	printf("*****1.add *****\n");
	printf("*****2.sub *****\n");
	printf("*****3.mul *****\n");
	printf("*****4.div *****\n");
}
int add(int i, int j)
{
	return i + j;
}
int sub(int i, int j)
{
	return i - j;
}
int mul(int i, int j)
{
	return i * j;
}
int div(int i, int j)
{
	return i / j;
}
int main()
{
	int n = 0;
	int i = 0;
	int j = 0;
	int ret = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &n);
		switch (n)
		{
		case 0:
				printf("退出程序\n");
				break;
			case 1:
				printf("请输入两个 *** 作数:");
				scanf("%d %d", &i, &j);
				ret = add(i, j);
				printf("%d\n", ret);
				break;
			case 2:
				printf("请输入两个 *** 作数:");
				scanf("%d %d", &i, &j);
				ret = sub(i, j);
				printf("%d\n", ret);
				break;
			case 3:
				printf("请输入两个 *** 作数:");
				scanf("%d %d", &i, &j);
				ret = mul(i, j);
				printf("%d\n", ret);
				break;
			case 4:
				printf("请输入两个 *** 作数:");
				scanf("%d %d", &i, &j);
				ret = div(i, j);
				printf("%d\n", ret);
				break;
			default:
				printf("选择错误,请重新选择\n");
				break;
		}
	} while (n);
	return 0;
}


可以看到一个简单的计算器已经实现了,但是有很多代码重复了:

能不能更简单一点呢?
答案是可以的!

#include
void menu()
{
	printf("*****0.exit*****\n");
	printf("*****1.add *****\n");
	printf("*****2.sub *****\n");
	printf("*****3.mul *****\n");
	printf("*****4.div *****\n");
}
int add(int i, int j)
{
	return i + j;
}
int sub(int i, int j)
{
	return i - j;
}
int mul(int i, int j)
{
	return i * j;
}
int div(int i, int j)
{
	return i / j;
}
void calc(int(*p)(int ,int ))//函数指针(计算器)
{
	int i = 0;
	int j = 0;
	int ret = 0;
	printf("请输入两个 *** 作数:");
	scanf("%d %d", &i, &j);
	ret = p(i, j);
	printf("%d\n", ret);
}
int main()
{
	int n = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &n);
		switch (n)
		{
		case 0:
			printf("退出程序\n");
			break;
		case 1:
			calc(add);
			break;
		case 2:
			calc(sub);
			break;
		case 3:
			calc(mul);
			break;
		case 4:
			calc(div);
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (n);
	return 0;
}


可以看出代码变得更简单了,函数变得不那么冗余了。当然还可以让这个代码变得更简洁,我们下面将


七、函数指针数组 1、概念

函数指针数组是一个数组,数组里面的元素都是函数指针。所以函数指针数组是一个存放函数指针的数组。


2、代码
int( * p [10] )( )


3、小例子
#include
void menu()
{
	printf("*****0.exit*****\n");
	printf("*****1.add *****\n");
	printf("*****2.sub *****\n");
	printf("*****3.mul *****\n");
	printf("*****4.div *****\n");
}
int add(int i, int j)
{
	return i + j;
}
int sub(int i, int j)
{
	return i - j;
}
int mul(int i, int j)
{
	return i * j;
}
int div(int i, int j)
{
	return i / j;
}
int main()
{
	int(*p[4])(int, int) = { add,sub,mul,div };
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		int ret = p[i](8, 4);
		printf("%d\n", ret);
	}
	return 0;
}


可以看到将函数指针放到数组里面是很便捷的,接下来运用一下函数指针数组

4、转移表

上面我们做了一个简单的计算器,但是当计算器需要计算各种方法的时候(比如说取余,异或,按位,移位)难道要一个个的调用函数指针吗?
其实不用那么麻烦

#include
void menu()
{
	printf("*****0.exit*****\n");
	printf("*****1.add *****\n");
	printf("*****2.sub *****\n");
	printf("*****3.mul *****\n");
	printf("*****4.div *****\n");
	printf("*****5.qy  *****\n");
	printf("*****6.awy *****\n");
	printf("*****7.awh *****\n");
	printf("*****8.yh  *****\n");
	printf("*****9.ljy *****\n");
	printf("*****10.ljh*****\n");
	printf("*****11.zy *****\n");
	printf("*****12.yy *****\n");
}
int add(int i, int j)
{
	return i + j;
}
int sub(int i, int j)
{
	return i - j;
}
int mul(int i, int j)
{
	return i * j;
}
int div(int i, int j)
{
	return i / j;
}
int qy(int i, int j)
{
	return i % j;
}
int awy(int i, int j)
{
	return i & j;
}
int awh(int i, int j)
{
	return i | j;
}
int yh(int i, int j)
{
	return i ^ j;
}
int ljy(int i, int j)
{
	return i && j;
}
int ljh(int i, int j)
{
	return i || j;
}
int zy(int i, int j)
{
	return i << j;
}
int yy(int i, int j)
{
	return i >> j;
}
void calc(int (*pfarr)(int,int))
{
	int n = 0;
	int i = 0;
	int j = 0;
	int ret = 0;
	printf("请输入两个 *** 作数:");
	scanf("%d %d", &i, &j);
	ret = pfarr(i, j);
	printf("%d\n", ret);
}
int main()
{
	int n = 0;
	int(*pfarr[])(int, int) = { 0,add,sub,mul,div,qy,awy,awh,yh,ljy,ljh,zy,yy };
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &n);
		if (n == 0)
		{
			printf("退出程序\n");
		}
		else if (n >= 1 && n <= 12)
		{
			calc(pfarr[n]);
		}
		else
		{
			printf("选择错误\n");
		}
	} while (n);
	return 0;
}



可以看到函数指针数组的使用很方便


八、指向函数指针数组的指针

很多人看到这个名字就已经晕了,其实我们仔细分析会发现不难理解

int(*p[10])()

int ( * ( * parr ) [5] )( ) = &p

我们只需要了解指向函数指针数组的指针是什么样子就行,不用深究。当然,相信各位小伙伴们已经发现了,这个东西又是一个指针,我们又可以放到一个数组里面,像这样一直套娃下去…


九、回调函数 1、概念

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。


2、qsort函数 A、冒泡排序优化
#include
void bubble(int* arr, int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)//一共要排序多少躺
	{
		int flag = 1;//假设原来的数组内容已经是正确的顺序了
		for (j = 0; j < sz - 1 - i; j++)//一趟排序是怎么样的
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;//如果flag等于0那么就表示数组内容顺序有问题,已经排序完一次了
			}
		}
		if (flag == 1)//如果顺序没有问题就退出
		{
			break;
		}
	}
}
int main()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble(arr, sz);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

上面的冒泡排序我们已经就行优化了,但是不管再怎么优化也只能排列整型数据,能排浮点型、字符、结构体类型的数据吗?
显而易见是不能的,那么就要用到我们的qsort函数了

B、qsort函数(重点)

qsort函数就是快速排序

上图中是qsort函数的具体内容,需要引头文件stdlib.h
qsort函数4个内容:
1、排序内容的起始地址;
2、待排序的元素个数;
3、待排序元素字节大小;
4、排序的方法
注:qsort默认是排升序的
下面我们会用qsort来排序整型数据和结构体数据


void*指针

void*是无具体类型的指针,可以接受任意类型的地址
void*是无具体类型的指针,所以不能解引用 *** 作和+-整数的 *** 作

qsort排序整型数据类型
#include
#include
int cmp(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
int main()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

可以看出用了qsort函数之后结果不仅正确了,而且还节约时间,空间,可以说是非常方便了。


qsort函数排序结构体数据类型
#include
#include
#include
struct stu
{
	char name[20];
	int age;
};
int cmp_by_name(const void* e1,const void* e2)
{
	return   strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
int cmp_by_age(const void* e1, const void* e2)
{
	return   ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
void test2()
{
	struct stu s[] = { {"zhangsan",15}, {"lisi",30} ,{"wangwu",20} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_by_name);
	qsort(s, sz, sizeof(s[0]), cmp_by_age);
}
int main()
{
	test2();//排序结构体数据
	return 0;
}

我们来看看结果:
名字排序:

年龄排序:

可以看到qsort把结构体的数据已经排序出来了,由此可见qsort的强大之处。


qsort实现冒泡函数
#include
void swap(char* b1, char* b2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *b1;
		*b1 = *b2;
		*b2 = tmp;
		b1++;
		b2++;
	}
}
void bubble(void*base,int sz,int width,int (*cmp)(const void* e1,const void* e2))
{
	int i = 0;
	int j = 0;
	int flag = 1;//假设原来的数组内容已经是正确的顺序了
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			//if (arr[j] > arr[j + 1])
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)>0)
			{
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
				flag = 0;//如果flag等于0那么就表示数组内容顺序有问题,已经排序完一次了
			}
		}
		if (flag == 1)//如果顺序没有问题就退出
		{
			break;
		}
	}
}
int cmp(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
void test3()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble(arr, sz, sizeof(arr[0]), cmp);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	test3();
	return 0;
}


小结

到目前为止,我们的指针进阶的内容基本上完成了,但是可没有结束哦!下面有几组笔试指针题目,有许多小陷阱,欢迎大家挑战哦!我也会为大家进行讲解的!


十、指针数组笔试题+讲解

我们不多说废话,直接题目+答案+讲解

第一组
#include
int main()
{
	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));
	return 0;
}



第二组
#include
int main()
{
	char a[] = { 'a','b','c','d','e','f' };
	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));
	return 0;
}



第三组(陷阱多) 补充知识点

strlen遇到#才停止,include不是字符串的内容,int只是结束标志

main(
) char[]
{
	= a'a', 'b' { ,'c','d','e','f'};printf ("%d\n"
	,strlen() );aprintf("%d\n"
	,strlen(+ 0)a ) ;printf("%d\n"
	,strlen(* ));aprintf("%d\n"
	,strlen([ 1]a));printf("%d\n"
	,strlen(& ));aprintf("%d\n"
	,strlen(& +1)a ) ;printf("%d\n"
	,strlen(& [0]a+1) ) ;return0}
	sizeof计算字符串的时候会把#算进去,因为include也占了空间位置 intmain

这一组题有许多陷阱,不能直接编译出结果,我为大家一一讲解:

可以看到还是有很多陷阱的,小伙伴们以后别像小编一样粗心大意哦!


第四组 补充知识点

(

)char
[ ]="abcdef"
{
	; aprintf( "%d\n" ,sizeof
	()); printf(a"%d\n",sizeof
	(+0) );a printf ("%d\n",sizeof
	(*)) ;printf(a"%d\n",sizeof
	([1] ))a;printf("%d\n",sizeof
	(&)) ;printf(a"%d\n",sizeof
	(&+1 ));a printf ("%d\n",sizeof
	(&[0 ]+1a)); return 0;}char a[]=“”;[]未表明个数,双引号定义字符串的时候会默认带上#。前提是方括号【】内的数字也就是空间足够大
	include intmain
(



第五组 补充知识点

)

char[
] ="abcdef";
{
	printf a("%d\n" , strlen(
	));printf ("%d\n"a,strlen(
	+0)) ;printfa ( "%d\n",strlen(
	*)); printf("%d\n"a,strlen(
	[1]) );aprintf("%d\n",strlen(
	&)); printf("%d\n"a,strlen(
	&+1) );printfa ( "%d\n",strlen(
	&[0] +1)a);return 0 ;}双引号自带#include  
	int main(
)

这一组代码也有陷阱,没有具体答案哦:

其实只要找到char就很简单啦!


第六组
*=
"abcdef" ;printf(
{
	"%d\n", a sizeof ()
	);printf( "%d\n",asizeof(+
	1)); printf(a "%d\n" ,sizeof(*
	));printf ("%d\n",asizeof([
	0])) ;printfa("%d\n",sizeof(&
	));printf ("%d\n",asizeof(&
	+1)) ;printf(a "%d\n" ,sizeof(&
	[0]+ 1))a;return0 ; }}#include
	int main(
)

char



第七组
[]
= "abcdef";printf
{
	( a"%d\n", strlen ()
	);printf( "%d\n",astrlen(+
	1)); printf(a "%d\n" ,strlen(*
	));printf ("%d\n",astrlen([
	0])) ;printfa("%d\n",strlen(&
	));printf ("%d\n",astrlen(&
	+1)) ;printf(a "%d\n" ,strlen(&
	[0]+ 1))a;return0 ; }我们之前说过二维数组数组名代表的就是第一行数组的地址#include  
	int main(
)

直接分析:


第八组 补充知识点

int

[3
] [4]
{
	= a0};printf("%d\n" , { sizeof ()
	);printf( "%d\n",asizeof([
	0][0 ])a);printf("%d\n",sizeof([
	0])) ;printfa("%d\n",sizeof([
	0]+1 ))a;printf("%d\n",sizeof(*
	([0] +1))a);printf ( "%d\n",sizeof(+
	1)); printf(a"%d\n",sizeof(*
	(+1) ));printfa ( "%d\n",sizeof(&
	[0]+ 1))a;printf("%d\n",sizeof(*
	(&[0 ]+1))a);printf ( "%d\n",sizeof(*
	));printf ("%d\n",asizeof([
	3])) ;returna0;}#includeint
	main ()
int



第九组
[5
] =1,
{
	2 a,3, 4 { ,5};int*=(int *)
	(& ptr + 1);printf("%d,%d"a , *(+
	1),* (-a 1 )); return0ptr ; }#includestruct
	stu int;
char


画个图就解决了:


第十组
*;
short ;
{
	char num[
	2] a;
	short date[
	4 b];}*
	; arrintmain()
=(pstruct
stu *)0x100000
{
	p ; printf( "%p\n",+0x1)
	;printf("%p\n" p , (unsignedlong
	)+0x1) ;printf ("%p\n"p , (unsignedint
	*)+0x1 ); return0;p } #includeint
	main ()
int


第十一组
[4
] =1,
{
	2 a,3, 4 { };int*=(int *)
	(& p1 + 1);int*=a ( int*)
	(( p2 int )+1);printf("%x,%x"a , [-1
	],*) p1;return0;} #p2includeint
	main ()
int


第十二组
[3
] [2]
{
	= a(0,1), ( { 2,3),(4,5)};int*;=[ 0]
	;printf p(
	p "%d\n" a,[0]
	);return0 p;}#includeint
	main ()
int

这个题其实很简单:


第十三组
[5
] [5]
{
	; aint(*)[4]
	;=;pprintf("%p,%d\n",&
	p [ a4
	][2]-p&[4][2],a&[4][2] -p&[4][2 ] )a;return0;}#includeint
	main ()
int


第十四组
[2
] [5]
{
	= a1,2,3, 4 { ,5,6,7,8,9,10};int*=(int *)
	(& arr1 + 1);int*=a ( int*)
	(* arr2 ( +1));printf(a "%d,%d\n" ,*(-
	1),* (-arr1 1 )); return0arr2 ; }#includeint
	main ()
char


第十五组
*[
] ="work",
{
	"at", a"alibaba"} ; { char**=; ++;
	printf("%s\n" pa , a*
	pa);
	return0;} #paincludeint
	main ()
char


第十六组
*[
] ="ENTER",
{
	"NEW", c"POINT", "FIRST" { };char**[] =+
	3,+ cp2, + { c 1 ,}c ; char*c * *=c ;printf
	("%s\n",* cpp * cp++
	);printf( "%s\n",*cpp--*
	+++3) ;printf("%s\n"cpp,*[-
	2]+3 )cpp;printf("%s\n",[-1
	][-1 cpp]+1);return0;}本章花费了小编好几天时间,干货还是有的,希望能够给各位小伙伴带来新的收获,同时希望各位观众能够点点赞,最后一道题可能一些观众不理解,如果不理解的话可以私信小编,小编为为你详细解答的,希望各位小伙伴能够与小编一起进步,我们下期见啦!
	 


这一题小编在本子上做了,有点乱,大家可以自己做做这道题:



总结

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1325115.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-12
下一篇2022-06-12

发表评论

登录后才能评论

评论列表(0条)

    保存