2009-06-03 56 views
5

使用c風格的字符串時,如何將字符分配給字符指針指向的內存地址?例如,在下面的示例中,我想將num更改爲「123456」,因此我嘗試將p設置爲'0'所在的數字,並嘗試用'4'覆蓋它。謝謝。這段代碼爲什麼修改一個字符串不起作用?

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    char* num = (char*)malloc(100); 
    char* p = num; 

    num = "123056"; 

    p = p+3; //set pointer to where '4' should be 
    p = '4'; 

    printf("%s\n", num); 

    return 0; 
} 
+0

的可能的複製[爲什麼寫有「字符\ * S」,而不是「char形式\ [\]」初始化字符串時,我得到一個分段錯誤? ](http://stackoverflow.com/questions/164194/why-do-i-get-a-segmentation-fault-when-writing-to-a-string-initialized-with-cha) – jww 2016-10-20 11:07:51

回答

12

該代碼將無法正常工作,只是因爲該行:

num = "123056"; 

改變num從分配的內存點離開(和p仍然指向內存使他們不再在同一位置)到什麼是最可能的只讀內存。您不允許更改屬於字符串文字的內存,這是未定義的行爲。

您需要:

#include <stdio.h> 
#include <stdlib.h> 
int main (void) { 
    char *num = malloc (100); // do not cast malloc return value. 
    char *p = num; 

    strcpy (num, "123056"); // populate existing block with string. 

    p = p + 3;    // set pointer to where '0' is. 
    *p = '4';     // and change it to '4'. 

    printf ("%s\n", num); // output it. 

    return 0; 
} 
0

只要使用*p = '4'; ...!

+0

取消引用它沒有工作。字符串'num'是不可變的嗎?我在Linux上用cc編譯。 – 2009-06-03 05:37:54

+0

這是錯誤的;它應該是'4',而不是4. – 2009-06-03 05:46:11

+0

是的,字符串文字可能被分配在標記爲只讀的內存中,並且任何嘗試寫入它都會導致運行時錯誤。 – sharptooth 2009-06-03 05:47:28

13

首先,當你這樣做:

num = "123056"; 

你沒有複製字符串「123056」堆由malloc()分配的區域。在C語言中,分配char *指針字符串文本值等同於設置它爲一個常數 - 即等同於:

char str[] = "123056"; 

所以,你剛剛完成有你放棄了你的唯一參考由malloc()分配的100字節堆區域,這就是爲什麼您的後續代碼不能打印正確的值; 'p'仍然指向由malloc()分配的堆的區域(因爲num在作業時指向它),但num不再。

我假設你實際打算做的是將拷貝到的字符串「123056」到那個堆區。以下是如何做到這一點:

strcpy(num, "123056"); 

雖然,這是多種原因更好的做法:

strncpy(num, "123056", 100 - 1); /* leave room for \0 (null) terminator */ 

如果你剛剛做:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int  main(void) { 
     char *num = malloc(100); 
     char *p = num; 

     strncpy(num, "123056", 100 - 1); 

     p = p + 3; 
     *p = '4'; 

     printf("%s\n", num); 

     return 0; 
} 

你會得到的正確的結果:

123456 

您可以承攬此操作:

p = p + 3; 
*p = '4'; 

...,避免迭代指針,通過deferencing如下:

*(p + 3) = '4'; 

其他一些注意事項:

  • 雖然常見文體練習中,將malloc()的返回值轉換爲(char *)是不必要的。 C語言保證了void *類型的轉換和對齊。

  • 總是檢查返回值malloc()。如果堆分配失敗(即你內存不足),那麼它將爲NULL,並且此時應該退出程序。

  • 根據實施情況,在某些情況下,由malloc()分配的內存區域可能包含陳舊垃圾。它始終是分配到零之後出來一個好主意:

    memset(num, 0, 100); 
    
  • 千萬不要忘了你的free()堆!在這種情況下,程序將退出並且操作系統會清理垃圾,但如果您沒有養成這種習慣,您很快就會發生內存泄漏。

所以,這裏的 「最佳實踐」 的版本:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int  main(void) { 
     char *num, *p; 

     /* 
     * Don't take 1-byte chars for granted - good habit to get into. 
     */ 

     num = malloc(sizeof(char) * 100); 

     if(num == NULL) 
       exit(1); 

     memset(num, 0, sizeof(char) * 100); 

     p = num; 

     strncpy(num, "123056", 100 - 1); 

     *(p + 3) = '4'; 

     printf("%s\n", num); 

     free(num); 

     return 0; 
} 
+1

感謝您的好記憶管理技巧。這些提示適用於來自自動垃圾收集語言的人! – 2009-06-03 17:47:26

0

嗯,你知道p是指針類型。它存儲char'0'的地址。如果您將p賦值爲'4'。它將以'4'作爲地址。但是,地址'4'是非法的。您可以使用'*'運算符來獲取存儲在p中的地址值。

1

除了其他人指出的* p問題之外,您還有內存使用問題。您有一個100字節的緩衝區,內容未知。你有另一個7字節的緩衝區,包含字符串「123056」和一個空終止符。你這樣做:

  1. NUM被設置爲指向100字節的緩衝區
  2. p被設置爲指向爲num;即它指向100字節緩衝區
  3. 您將num重置爲指向7字節緩衝區; p被仍然指向100字節的緩衝區
  4. 您使用p來修改100字節的緩衝區
  5. 然後使用NUM打印出7字節的緩衝區

所以你不打印相同緩衝你正在修改。

相關問題