抓住指針的精髓,纔算掌握了 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

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