目录
大家可能听说过这样一句话,没学过指针就是没学过C语言。指针确实时C语言的一大特色,更是C语言的一大核心。但是指针的学习也没有大家想象的这么难。今天就带大家一起来深入学习一下指针。
指针有很多类型:
- //整形指针
- int* a;
- //字符指针
- char* b;
- //浮点型指针
- double* c;
- //自定义结构体指针
- struct S
- {
- int a;
- char b;
- }*ss;
指针的类型代表了,指针指向的空间存储的数据类型,同时也意味着,指针在解引用时的访问能力。(例如:字符指针解引用一次就只可以解引用访问一个字节)
今天特别说以一下字符指针:
const char* ch = "hahaha";
大家看一下这段代码,大家想一下 ch 里面存储的是什么?是存储的字符串"hahaha"? 还是字符串的第一个字符的地址?
const char* ch = "hahaha";
这段代码让很多小伙伴误以为是,把字符串放进 ch 里面,其实是把常量字符串的第一个字符放进 ch 里面。
看一个题目:
-
- int main()
- {
- char str1[] = "hello bit.";
- char str2[] = "hello bit.";
- const char* str3 = "hello bit.";
- const char* str4 = "hello bit.";
- if (str1 == str2)
- {
- printf("str1 and str2 are same\n");
- }
- else
- {
- printf("str1 and str2 are not same\n");
- }
- if (str3 == str4)
- {
- printf("str3 and str4 are same\n");
- }
- else
- {
- printf("str3 and str4 are not same\n");
- }
- return 0;
- }
大家可以想一下执行结果。
这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4不同。
大家可以猜一下,这指针数组,到底是指针还是数组?
答案是:数组。
- //整形数据,可以存储多个整形数据
- int arr[10];
- //字符数组,可以存储字符或者字符串
- char ch[10];
- //指针数组,是不是可以存储多个指针?
没错,指针数组就是用于存储指针的数组。
int* arr[10];
我们前面说到,字符指针可以存储一个常量字符串的首字符地址,那我们就可以用一个指针数组来存起来。
- int main()
- {
- char* str1 = "I'm ikun";
- char* str2 = "You are ikun";
- char* str3 = "sing jump rap basketball";
- //数组指针:
- char* kun[3] = { str1,str2,str3 };
- int sz = sizeof(kun) / sizeof(kun[0]);
- int i = 0;
- for (i = 0; i < 3; i++)
- {
- printf("%s\n", kun[i]);
- }
- return 0;
- }
运行结果:
刚刚讲了指针数组,现在再来聊一下数组指针,这次数组指针就是一个指针了。
整形指针: int * pint; 能够指向整形数据的指针。
浮点型指针: float * pf; 能够指向浮点型数据的指针。
那数组指针应该是:能够指向数组的指针。
int(*p)[10];
说明:
所以p是一个指针,指向一个数组,叫数组指针。这里要注意:[ ] 的优先级要高于*号的,所以必须加上( )来保证p先和*结合。
对于下面的数组:
int arr[10];
arr 和 &arr 分别是啥?我们知道arr是数组名,数组名表示数组首元素的地址。那&arr数组名到底是啥?
我们看一段代码:
- #include
- int main()
- {
- int arr[10] = {0};
- printf("%p\n", arr);
- printf("%p\n", &arr);
- return 0;
- }
(%p 打印地址)
运行结果:
有的小伙伴看到这里是不是就以为,这不是一样的嘛。别急我们接着看一段代码。
- #include
- int main()
- {
- int arr[10] = { 0 };
- printf("arr = %p\n", arr);
- printf("arr+1 = %p\n", arr + 1);
- printf("\n");
- printf("&arr= %p\n", &arr);
- printf("&arr+1= %p\n", &arr + 1);
- return 0;
- }
运行结果:
我们可以就看到,arr + 1 以后跳过了4个字节,&arr +1 以后跳过了40个字节,40是个字节归刚好是,arr数组十个元素的总大小,又因为数组在内存中是连续存放的。所以&arr + 1 就跳过了整个数组。所以这里&arr 代表的就是整个数组的地址。如果需要一个指针来存储这个数组地址,那就会用到我们的数组指针。
- int arr[10] = { 0 };
- int(*arrp)[10] = &arr;
二维数组数组名:一维数组的数组名是首元素的地址,二维数组的数组名也是首元素的地址,这里二维数组的首元素是第一个一位数组,因为二维数组也可以看作是由数个一维数组组成的,二维数组的数组名就代表了第一个一维数组的地址。
所以我们在函数传参数的时候,不仅可以以数组的形式去接收,还可以以指针的形式去接收:
- #include
- //数组的形式接收
- void print_arr1(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 print_arr2(int(*arr)[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");
- }
- }
- int main()
- {
- int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
- print_arr1(arr, 3, 5);
- //数组名arr,表示首元素的地址
- //但是二维数组的首元素是二维数组的第一行
- //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
- //可以数组指针来接收
- printf("\n");
- print_arr2(arr, 3, 5);
- return 0;
- }
运行结果当然也是一样的:
今天的关于指针的讲解先讲到这。欲知后事如何,请看下期。
生命不息,奋斗不止!只要相信,只要坚持,只要你真的是用生命在热爱,那一定是天赋使命使然,那就是一个人该坚持和努力的东西,无论梦想是什么,无论路有多曲折多遥远,只要是灵魂深处的热爱,就会一直坚持到走上属于自己的舞台!真正成功的人生,不在于成就的大小,而在于你是否努力地去实现自我,喊出自己的声音,走出属于自己的道路。加油,诸君,山顶见!