1. 程式人生 > >C語言指標使用中的常見錯誤

C語言指標使用中的常見錯誤

      指標的作用特別強,對許多問題是必須的。同時,偶爾錯用指標,會帶來意想不到的錯誤,甚至是災難性的後果。

      指標錯誤難以定位,因為指標本身並沒有問題。問題在於,通過錯誤指標操作時,程式對未知記憶體區進行讀寫操作。讀操作時,最壞的情況是取得無用資料;而寫操作時,可能沖掉其他程式碼或資料。

      (一)使用未初始化的指標(uninitialized pointer)

int main(void)
{
  int x, *p;

  x = 10;
  *p = x; //錯誤,指標未初始化

  return 0;
}
      上述程式將值10寫到未知的記憶體位置,因為從未向指標p賦值,p的內容不確定。

      (二)誤解指標的用法,將值當做地址賦給指標

#include <stdio.h>

int main(void)
{
  int x, *p;

  x = 10;
  p = x;    //錯誤,應該是p=&x,指標儲存的是地址,而不是值

  printf("%d", *p);

  return 0;
}

      (三)這種錯誤是對記憶體中資料存放位置的錯誤假定。比較指向不同物件的指標時,容易產生意外結果。例如:
char s[80], y[80];
char *p1, *p2;

p1 = s;
p2 = y;
if(p1 < p2) . . .    //錯誤,不能確保資料處於記憶體的同樣位置,也不能確保各種機器都用同樣的格式儲存資料

      類似的錯誤是想當然地以為同時定義的兩個陣列在記憶體區是順序排列,從而簡單地對指標增值,期望像使用兩者組成的一個數組那樣跨越陣列邊界。例如:
int first[10], second[10];
int *p, t;

p = first;
for(t=0; t<20; ++t)  *p++ = t;

      (四)
/* 這段程式有錯誤 */
#include <string.h>
#include <stdio.h>

int main(void)
{
  char *p1;
  char s[80];

  p1 = s;
  do {
    gets(s);  /* read a string */

    /* print the decimal equivalent of each
       character */
    while(*p1) printf(" %d", *p1++);

  } while(strcmp(s, "done"));

  return 0;
}

      上述程式通過p1打印出與s中諸字元關聯的ASCII值。問題是隻對p賦值(s的地址)一次。第一輪迴圈中,p1指向s中首字元。第二輪迴圈時,因為未再置成s的起點,p值從第一輪的結束點繼續。此時,p可能指向另一個串,另一個變數,甚至程式的某一段。正確程式應該是:
#include <string.h>
#include <stdio.h> 

int main(void)
{
  char *p1;
  char s[80];

  do {
    p1 = s; /* reset p1 to beginning of s */
    gets(s);  /* read a string */

    /* print the decimal equivalent of each
       character */
    while(*p1) printf(" %d", *p1++);

  } while(strcmp(s, "done"));

  return 0;
}