
大家好啊,因为上个星期生病的原因,没有及时更新,本期这就补上。
本期主要内容是深入解析指针,让大家能够进一步了解指针,希望对各位小伙伴有所帮助!
- 前言
- 一、指针的基本概念
- 二、字符指针
- 三、指针数组
- 四、数组指针
- 小知识点——数组名与&数组名
- 数组指针的使用
- 小结
- 五、 数组参数与指针参数
- 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、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;
}
可以看到将函数指针放到数组里面是很便捷的,接下来运用一下函数指针数组
上面我们做了一个简单的计算器,但是当计算器需要计算各种方法的时候(比如说取余,异或,按位,移位)难道要一个个的调用函数指针吗?
其实不用那么麻烦
#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函数了
qsort函数就是快速排序
上图中是qsort函数的具体内容,需要引头文件stdlib.h
qsort函数4个内容:
1、排序内容的起始地址;
2、待排序的元素个数;
3、待排序元素字节大小;
4、排序的方法
注:qsort默认是排升序的
下面我们会用qsort来排序整型数据和结构体数据。
void*指针
qsort排序整型数据类型
void*是无具体类型的指针,可以接受任意类型的地址
void*是无具体类型的指针,所以不能解引用 *** 作和+-整数的 *** 作
#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也占了空间位置 int;
main
这一组题有许多陷阱,不能直接编译出结果,我为大家一一讲解:
可以看到还是有很多陷阱的,小伙伴们以后别像小编一样粗心大意哦!
第四组 补充知识点
(
)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;}本章花费了小编好几天时间,干货还是有的,希望能够给各位小伙伴带来新的收获,同时希望各位观众能够点点赞,最后一道题可能一些观众不理解,如果不理解的话可以私信小编,小编为为你详细解答的,希望各位小伙伴能够与小编一起进步,我们下期见啦!
这一题小编在本子上做了,有点乱,大家可以自己做做这道题:
总结
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)