抓住指针的精髓,才算掌握了 C 语言的灵魂!

学习C肯定会碰到指针,指针是C的灵魂。所以学好指针很关键,这里写一些指针方面的容易错的或者易混淆的知识点还有自己不会的盲点,以便之后复习时用。

数组传参和数组形参

1.1 数组传参

如果函数遇到数组传参的,不论是什么形式的形参,只要是数组,那么被调函数都将这个形参都当做指针来使用。

  `#include "stdio.h"``PrintArray(int *a, int num)``{``int i;``for (i = 0; i < num; i++)``{``printf("%5d", a[i]);``}``printf("\n");``}``int main(void)``{``int a[] = { 3,4,5,6,7,7,8 };``int num = sizeof(a) / sizeof(a[0]);``PrintArray(a, num);``system("pause");``}`

一般我们使用数组传参。

下面还有一种形参表示方法也很常用,效果其实是一样的。

  `#include "stdio.h"``PrintArray(int *a, int num)``{``int i;``for (i = 0; i < num; i++)``{``printf("%5d", a[i]);``}``printf("\n");``}``PrintArray1(int a[], int num)``{``int i;``for (i = 0; i < num; i++)``{``printf("%5d", a[i]);``}``printf("\n");``}``int main(void)``{``int a[] = { 3,4,5,6,7,7,8 };``int num = sizeof(a) / sizeof(a[0]);``PrintArray(a, num);``PrintArray1(a, num);``system("pause");``}`

其实做为一个学习者,有一个学习的氛围跟一个交流圈子特别重要这里我推荐一个C语言C++交流群1075673198,不管你是小白还是转行人士欢迎入驻,大家一起交流成长。

甚至还有一种方法:

  `#include "stdio.h"``PrintArray(int *a, int num)``{``int i;``for (i = 0; i < num; i++)``{``printf("%5d", a[i]);``}``printf("\n");``}``PrintArray1(int a[], int num)``{``int i;``for (i = 0; i < num; i++)``{``printf("%5d", a[i]);``}``printf("\n");``}``PrintArray2(int a[7], int num)``{``int i;``for (i = 0; i < num; i++)``{``printf("%5d", a[i]);``}``printf("\n");``}``int main(void)``{``int a[] = { 3,4,5,6,7,7,8 };``int num = sizeof(a) / sizeof(a[0]);``PrintArray(a, num);``PrintArray1(a, num);``PrintArray2(a, num);``system("pause");``}`

1.2 数组传参实质

数组实质传的都是指针,不论什么表现形式。

  `#include "stdio.h"``PrintArray(int *a, int num)``{``int i,num1;``num1 = sizeof(a) / sizeof(a[0]);``printf("num = %5d",num1);``for (i = 0; i < num; i++)``{``printf("%5d", a[i]);``}``printf("\n");``}``PrintArray1(int a[], int num)``{``int i,num1;``num1 = sizeof(a) / sizeof(a[0]);``printf("num = %5d", num1);``for (i = 0; i < num; i++)``{``printf("%5d", a[i]);``}``printf("\n");``}``PrintArray2(int a[7], int num)``{``int i,num1;``num1 = sizeof(a) / sizeof(a[0]);``printf("num = %5d", num1);``for (i = 0; i < num; i++)``{``printf("%5d", a[i]);``}``printf("\n");``}``int main(void)``{``int a[] = { 3,4,5,6,7,7,8 };``int num = sizeof(a) / sizeof(a[0]);``PrintArray(a, num);``PrintArray1(a, num);``PrintArray2(a, num);``system("pause");``}`

可以看到num1的值均为1。

实参都是数组,形参都是指针,无论什么形式。

数组首元素地址和整个数组地址

  `#include "stdio.h"``int main(void)``{``int a[10];``printf("a的大小 = %d\n", sizeof(a));``printf("a = %d\n", a);``printf("a + 1 = %d\n", a + 1);``printf("&a = %d\n", &a);``printf("&a + 1 = %d\n", &a + 1);``system("pause");``}`

image

从这组输出我们可以看到几点:

a数组大小是40。因为一个int是4字节,一共10个。

数组a和&a值一样

但是a是数组首元素地址,而&a是整个数组地址。

这个原因也导致另外两个值不同。a+1就是第二个元素地址,偏移4字节

&a+1是相当于偏移整个数组大小,也就是40字节。

变量在内存中的位置

变量在内存中有四个地方可以存放,读取修改变量实质都是通过指针修改。

3.1 变量存放的区域

image

3.2 常量例子

  `#include "stdio.h"``char *GetChar1(void)``{``char *p1 = "abcdefg";``return p1;``}``char *GetChar2(void)``{``char *p2 = "abcdefg1";``return p2;``}``int main(void)``{``char *p1 = NULL;``char *p2 = NULL;``p1 = GetChar1();``p2 = GetChar2();``//打印数据``printf("p1 = %s\n", p1);``printf("p2 = %s\n", p2);``//打印地址``printf("p1 = %5d\n", p1);``printf("p2 = %5d\n", p2);``system("pause");``}`

在内存中表示为:

image

其实做为一个学习者,有一个学习的氛围跟一个交流圈子特别重要这里我推荐一个C语言C++交流群1075673198,不管你是小白还是转行人士欢迎入驻,大家一起交流成长。

因为GetChar函数里面都是指针所以都放在栈区,而常量都在全局区。

当被调函数return之后,上面两个指针被释放,然后将地址赋给main函数里面的指针,他们就指向相应的值。

接下来,还有一个易错的点!!!

  `#include "stdio.h"``char *GetChar1(void)``{``char *p1 = "abcdefg1";``return p1;``}``char *GetChar2(void)``{``char *p2 = "abcdefg1";``return p2;``}``int main(void)``{``char *p1 = NULL;``char *p2 = NULL;``p1 = GetChar1();``p2 = GetChar2();``//打印数据``printf("p1 = %s\n", p1);``printf("p2 = %s\n", p2);``//打印地址``printf("p1 = %5d\n", p1);``printf("p2 = %5d\n", p2);``system("pause");``}`

image

main函数里面指针地址是一样的

[图片上传失败…(image-2ba3cf-1591429660089)]

3.3 堆和栈例子

用户自己申明的变量是在堆中存放的,只有用户释放。

  `#include "stdio.h"``char *GetString(int num)``{``char *s = NULL;``s = (char *)malloc(sizeof(char)*num);``if (s == NULL)``{``return NULL;``}``return s;``}``int main(void)``{``char *p1 = NULL;``p1 = GetString(10);``if (p1 == NULL)``{``return;``}``strcpy(p1, "abcdefg");``printf("%s\n", p1);``system("pause");``}`

内存中分布:

image.png

当GetString()被调用后,s释放之后,malloc分配的空间还是存在,所以还能继续打印。

接下来的问题在实际写的过程中会犯错:

  `#include "stdio.h"``char *GetString(int num)``{``char *s = NULL;``s = (char *)malloc(sizeof(char)*num);``if (s == NULL)``{``return NULL;``}``return s;``}``char *GetString1(void)``{``char s1[10];``strcpy(s1, "qwerty");``printf("%s\n", s1);``return s1;``}``int main(void)``{``char *p1 = NULL;``char *p2 = NULL;``p1 = GetString(10);``if (p1 == NULL)``{``return;``}``p2 = GetString1();``strcpy(p1, "abcdefg");``printf("%s\n", p1);``printf("%s\n", p2);``system("pause");``}`

这时的p2其实打印不出来或者程序死机了。这是因为GetString1()中的s1变量是申明在栈区中,当调用结束后,被释放了,那块区域中的qwerty就没了。但是地址还是那个10字节的起始地址,并没有全部return出来。

其他

内存中的栈是开口向下的。

image.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章