天天看點

深入學習C語言:指針易錯點剖析

作者:嵌入式講堂

指針是C語言中非常重要的概念,也是C語言差別于其他語言的重要特性之一。但是,指針的使用也是C語言中最容易出現錯誤的地方。在編寫程式時,如果不小心使用指針,可能會導緻程式崩潰或産生其他未知錯誤。本篇文章将從十個常見的指針易錯點入手,詳細剖析指針的使用問題,幫助讀者更深入地了解指針的使用。

目錄

  • 空指針問題
  • 野指針問題
  • 非法指針問題
  • 懸空指針問題
  • 數組越界問題
  • 算術指針問題
  • 記憶體洩漏問題
  • 多級指針問題
  • 指針類型不比對問題
  • 指針引用問題

空指針問題

指針未初始化或被賦為NULL時,會導緻通路空指針而出現錯誤。例如:

int *p;
*p = 10; // p為未初始化的指針,會導緻錯誤           

解決方法:在使用指針之前,一定要先将其初始化或賦為NULL。

int *p = NULL;
p = (int *)malloc(sizeof(int));
*p = 10;           

野指針問題

指針被釋放後,沒有将其賦為NULL,繼續使用該指針時會産生野指針問題。例如:

int *p = (int *)malloc(sizeof(int));
free(p);
*p = 10; // p為野指針,會導緻錯誤           

解決方法:在釋放指針後,一定要将其賦為NULL。

int *p = (int *)malloc(sizeof(int));
free(p);
p = NULL;           

非法指針問題

指針未指向有效的記憶體位址時會出現非法指針問題。例如:

int *p = (int *)0x12345678;
*p = 10; // p為非法指針,會導緻錯誤           

解決方法:在使用指針之前,一定要確定其指向有效的記憶體位址。

int a = 10;
int *p = &a;           

懸空指針問題

在函數中定義一個局部指針變量,并在函數結束後傳回指向該指針指向的記憶體空間時,該指針變量就變成了懸空指針。例如:

int *func() {
    int a = 10;
    int *p = &a;
    return p;
}

int *p = func();
*p = 20; // p為懸空指針,會導緻錯誤           

解決方法:盡量避免使用懸空指針。

int *func() {
    int *p = (int *)malloc(sizeof(int));
    *p = 10;
    return p;
}

int *p = func();
*p = 20;
free(p);           

數組越界問題

指針指向的位址超出數組範圍,通路非法記憶體區域,并有可能導緻程式崩潰。例如:

int a[10];
int *p = a + 20;
*p = 10; // p超出數組範圍,會導緻錯誤           

解決方法:在使用指針通路數組元素時,一定要確定指針指向的位址在數組範圍内。

int a[10];
int *p = a + 5;
*p = 10;           

算術指針問題

當指針進行指針運算時,需要確定結果仍然指向合法的記憶體位址。例如:

int a[10];
int *p = a + 5;
int *q = p + 10; // q超出數組範圍,會導緻錯誤           

解決方法:在進行指針運算時,一定要確定結果仍然指向合法的記憶體位址。

int a[10];
int *p = a + 5;
int *q = p + 2;           

記憶體洩漏問題

在使用malloc等動态記憶體配置設定函數時,必須及時使用free函數釋放配置設定的記憶體,否則會導緻記憶體洩漏。例如:

int *p = (int *)malloc(sizeof(int));
*p = 10;
// 沒有使用free函數釋放p指向的記憶體空間,會導緻記憶體洩漏           

解決方法:在使用malloc等動态記憶體配置設定函數配置設定記憶體空間後,一定要及時使用free函數釋放記憶體空間。

int *p = (int *)malloc(sizeof(int));
*p = 10;
free(p);           

多級指針問題

多級指針在使用時需要特别注意,容易造成混淆。例如:

int a = 10;
int *p = &a;
int **q = &p;
int ***r = &q;
printf("%d\n", ***r); // 輸出10           

解決方法:在使用多級指針時,一定要注意指針的層數和指針指向的資料類型。

int a = 10;
int *p = &a;
int **q = &p;
int ***r = &q;
*q = (int *)malloc(sizeof(int));
**q = 20;
printf("%d\n", ***r); // 輸出20
free(*q);           

指針類型不比對問題

指針類型不比對時會導緻資料類型不比對及其他錯誤。例如:

int a = 10;
float *p = &a; // p指向的類型與a的類型不比對,會導緻錯誤           

解決方法:在使用指針時,一定要確定指針指向的類型與所指向的變量類型比對。

int a = 10;
int *p = &a;           

指針引用問題

指針引用時需要特别注意指針符号的使用和位置,容易産生混淆和錯誤。指針符号"*"有兩種用法,一是用于聲明指針類型,二是用于指針引用。下面是一個指針引用的例子:

int a = 10;
int *p = &a;
int b = *p; // *p表示取p指向的值,而不是取p的值           

在以上代碼中,變量b的值是10,因為*p表示取p指向的值,即取a的值。如果代碼中将“*p”寫成“p”,則會發生編譯錯誤。是以,在使用指針引用時,一定要注意指針符号的使用和位置。

int a = 10;
int *p = &a;
int b = p; // error: invalid conversion from ‘int*’ to ‘int’           

總之,指針是C語言中較為重要的部分,也是難點之一。使用指針時需時刻保持警惕,注意指針的初始化、釋放、避免指針的錯位等。讀者如果能夠深入地了解指針,掌握其中的注意點,那麼寫出高效且健壯的程式并不是難事。

難題

以下是一道面試題:

#include <stdio.h>

void change(int* a, int b){
    int *c = &b;
    a = c;
}

int main(){
    int a = 5;
    int b = 10;
    int *p = &a;
    change(p, b);
    printf("%d\n", *p);
    return 0;
}           

以上代碼的輸出結果是什麼?為什麼?請在評論區留言讨論。

繼續閱讀