手机网站建设哪家好,做个电商平台需要哪些步骤,做细胞激活的母液网站,音乐培训如何做网站宣传#x1f680; 作者#xff1a;阿辉不一般 #x1f680; 你说呢#xff1a;不服输的你#xff0c;他们拿什么赢 #x1f680; 专栏#xff1a;爱上C语言 #x1f680;作图工具#xff1a;draw.io(免费开源的作图网站) 如果觉得文章对你有帮助的话#xff0c;还请点赞… 作者阿辉不一般 你说呢不服输的你他们拿什么赢 专栏爱上C语言 作图工具draw.io(免费开源的作图网站) 如果觉得文章对你有帮助的话还请点赞关注收藏支持博主如有不足还请指点博主及时改正感谢大家支持 文章目录 前言字符指针变量数组指针变量数组传参的本质✈️一维数组传参的本质✈️二维数组传参的本质总结 函数指针变量指针变量是什么 前言
在阿辉上一篇博客指针的基础篇中我们了解到指针的一些基础知识
指针变量是用来存放地址的变量通过指针可以找到所存地址指向的空间指针变量的大小与平台有关64位/32位平台大小为8字节/4个字节指针变量的类型决定了指针变量所指向的内存空间的类型和大小以及指针加减整数时移动的字节数指针的运算多级指针
有了以上对于指针的基础了解那么今天阿辉将为大家介绍C语言的指针部分包括字符指针、数组指针、数组传参的本质以及函数指针关注阿辉不迷路哦 内容干货满满接下来就跟着阿辉一起学习吧
字符指针变量
在指针的类型中我们知道有⼀种指针类型为字符指针 char* 一般我们这么用
int main()
{char ch w;char *pc ch;*pc w;return 0;
}其实它还可以这么用
int main()
{char* pstr hi bro;printf(%s\n, pstr);return 0;
}可能大家认为ptr里面存的是hi bro实际上ptr里面存的是字符串的首元素地址也就是h的地址这里大家有没有发现其实这和字符数组是一样的比如char arr[] “hi bro”数组名arr 也是首元素h的地址我们不妨把字符指针理解成字符数组但真的这么简单吗他们还是有两点不同我们接着看 第一点不同 我们可以看到当我们去改hi bro的内容时编译器直接报错这是因为hi bro是常量字符串而常量字符串被存储在程序的只读数据段.rodata中这个数据段是只读的意味着其中的数据在程序执行期间是不可修改的而字符数组是可以修改的 第二点不同
int main()
{char* str1 hi bro;char* str2 hi bro;char arr1[] hi bro;char arr2[] hi bro;if (str1 str2)printf(str1与str2空间相同\n);elseprintf(str1与str2空间不相同\n);if(arr1 arr2)printf(arr1与arr2空间相同\n);elseprintf(arr1与arr2空间不相同\n);return 0;
}输出
str1与str2空间相同
arr1与arr2空间不相同其实很简单这里str1和str2指向的是一个同一个常量字符串。C/C会把常量字符串存储到单独的一个内存区域当指针指向同一个字符串的时候他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以arr1和arr2不同str1和str2相同
数组指针变量
在之前阿辉的数组篇中讲到关于数组名的理解数组名是数组首元素的地址而取地址数组名是整个数组的地址那取地址数组名既然是地址那它应该存在什么类型的指针中呢没错就是数组指针 例如 int arr[5] { 0,1,2,3,4 };int(*p)[5] arr;p是变量名int(*)[5]是p变量的类型*指的是p是指针int[5]表示p指向的空间的类型是5个int类型变量的数组[]的优先级高于*所以要把*p用括号()括起来表明p是指针我们对p解引用*p就是arr也就是首元素地址我们对*p再次解引用就访问到数组第一个元素**p等价于arr[0]通过*(*p i)我们就可以遍历数组arr[5]那数组指针有何用别急我们接着看
数组传参的本质
✈️一维数组传参的本质
我们知道一维数组的数组名是首元素地址当我们传一个数组给函数时我们不会去在开辟一块同样的空间而是通过首元素地址访问数组这样有效的避免了空间的浪费 函数接收一维数组有三种方式例如
void test(int a[]);
void test(int a[5]);
void test(int* a);写法确实有三种不过前两种人模狗样的是数组毕竟传数组用数组接受很容易理解本质上还是指针包括[5]这个5屁用没有 注意 我个人的一点总结当一维数组名作为首元素地址传给函数后函数内部接收地址的形参不再具有数组名的性质仅仅是一个普通的指针 怎么理解呢我们接着看
void test(int a[])
{a;sizeof(a);
}
int main()
{int a[5] { 1,2,3,4,5 };test(a);return 0;
}上图是x86环境下的调试结果我们看到a类型是int * *是二级指针而并非数组指针sizeof(a)的值是4如果a还具有数组名的特性我们知道a将是int(*)[5]类型的数组指针而sizeof(a)的值将是20。这恰恰说明了当一维数组名作为首元素地址传给函数后函数内部接收地址的形参不再具有数组名的性质仅仅是一个普通的指针
✈️二维数组传参的本质
void test(int arr[][4]);
void test(int arr[3][4]);
行可以省略列不能省略那函数接收二维数组还有没有其他的方式 二维数组的数组名怎么理解呢二维数组可以理解为数组的数组二维数组的每一行理解为二维数组的一个元素二维数组的数组名同样是首元素地址只不过二维数组的首元素是第一行比如下图中二维数组arr[3][4]首元素是绿色的那一行一维数组所以二维数组的数组名arr表示一个int(*)[4]类型的数组指针 那么二维数组的传参就可以这么写void test(int (*arr)[4]) 例子
void test(int (*arr)[4])
{int i 0;int j 0;for (i 0; i 3; i){for (j 0; j 4; j){printf(%d , *(*(arr i) j));}printf(\n);}
}
int main()
{int arr[3][4] { {1,2,3,4},{2,3,4,5},{3,4,5,6} };test(arr);return 0;
}总结
一维数组的数组名是存放该数组首元素的一个指针二维数组的数组名是存放该数组首元素的一个数组指针一个数组int arr[5]{1,2,3,4,5}你可以用arr[1]和*(arr 1)两种方式访问数组的了第二个元素甚至可以1[arr]访问了解一下不建议使用。 *(arri)等价于arr[i]
函数指针变量
函数指针变量顾名思义是存放函数地址的指针函数也有地址吗 没错函数也有地址函数的函数名就是函数的地址 我们来看一段代码
#include stdio.h
void test()
{printf(hehe\n);
}
int main()
{printf(test: %p\n, test);printf(test: %p\n, test);return 0;
}输出:
test0xff44f68a
test0xff44f68a我们看到test与test打印出来的地址是一样的不仅打印出来的是一样的它俩本质也是一样的这俩等价这个多少有点多余 那函数指针如何创建呢其实与数组指针类似
int add(int x, int y)
{return x y;
}int main()
{int(*p)(int, int) add;p是函数指针变量名*表示p是一个指针int(*)(int,int)是p的类型int(int,int)表示p所指向的空间是函数函数的返回类型是int而且有两个int类型的形参return 0;
}那函数指针变量有什么用呢 我们可以通过函数指针变量来调用函数用上面的函数演示
int ret (*p)(3,5);
*P要用括号括起来因为函数调用操作符的优先级更高其实p、*p、add以及add这四个等价 所以调用add这个函数(*p)(3,5)和p(3,5)这俩都可以取地址和解引用都挺多余
指针变量是什么
大家看到这个标题或许很懵指针变量不就是用来存放地址的变量嘛讲这么多了还问
int add(int x, int y)
{return x y;
}int main()
{int(*padd)(int, int) add;int a 0;int* pa a;int arr[5] { 1,2,3,4,5 };int(*parr)[5] arr;return 0;
}上面这段代码中padd是int( * )(in,int)类型的函数指针变量pa是int类型的指针变量parr是int( * )[5]类型的数组指针变量其实add也是 int( * )(in,int)类型的函数指针变量a也是int类型的指针变量arr也是int( * )[5]类型的数组指针变量 地址是类似于0xff40688a这样的玩意add、a、arr里面存的不也是地址嘛SO他们也是指针变量 到这里阿辉今天对于C语言中一些特殊类型的指针的分享就结束了希望这篇博客能让大家有所收获, 如果觉得阿辉写得不错的话记得给个赞呗你们的支持是我创作的最大动力