2016-04-14 28 views
1

我在C中閱讀了關於動態數組的問題,但是我無法將答案與我的問題聯繫起來。如何動態地爲C中的字符串數組分配內存?

我使用fgets從stdin獲取命令,刪除換行符,然後希望將每個由空格分隔的命令存儲在動態分配的字符串數組中。然而,我正在分配和重新分配內存的正確方式遇到很多麻煩。我與clang編制和不斷收到分段錯誤11.然後我用-fsanitize=address並不斷收到:

==2286==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000eeb8 at pc 0x000108fb6f85 bp 0x7fff56c49560 sp 0x7fff56c49558 WRITE of size 8 at 0x60200000eeb8 thread T0

這裏是我的代碼:

// Sets a delimiter to split the input 
const char *seperator = " "; 

char *token = strtok(line, seperator); 

char **cmds = (char **) malloc(sizeof(char) * sizeof(*cmds)); 
// Adds first token to array of delimited commands 
cmds[0] = token; 

int count = 1; 
while (token != NULL) { 
    token = strtok(NULL, sep); 
    if (token != NULL) { 
     cmds = (char **) realloc(cmds, sizeof(char) * (count + 1)); 
     // Adds next token array of delimited commands 
     cmds[count] = token; 
     count++; 
    } 
} 
+0

的可能的複製[分段故障而無法理性內存分配如何,看起來好像沒什麼問題(http://stackoverflow.com/questions/35542391/segmentation-fault-but-unable-to-reason- how-memory-allocation-looks-fine-to-me) –

+0

不要將'malloc'和朋友的結果放在C中,並且C沒有字符串類型。這只是一種慣例。 – Olaf

回答

2

你沒有分配足夠的內存。 cmds是一個指針數組,因此每個元素是sizeof(char *)個字節,而不是sizeof(char)個字節。

在你想要的初始分配1 char *,然後在你想要的後續分配count + 1

此外,don't cast the return value of malloc,因爲這可以隱藏其他問題,並且不要忘記檢查故障。

char **cmds = malloc(sizeof(char *) * 1); 
if (cmds == NULL) { 
    perror("malloc failed"); 
    exit(1); 
} 
... 
     cmds = realloc(cmds, sizeof(char *) * (count + 1)); 
     if (cmds == NULL) { 
      perror("reallocfailed"); 
      exit(1); 
     } 
2

首先,sizeof(char)總是1的定義。並且編碼不會使您的代碼更具可讀性。

但是指向char的指針需要sizeof(char*)字節(取決於機器& ABI,通常是8或4字節)。如果使用GCC,我至少會建議用gcc -Wall -Wextra -g編譯你的代碼。

最後,我發現你的代碼有點低效。您在每個循環都致電realloc。我會維持一個變量含有分配的大小

int allocsize = 4; // allocated size in number of elements 
char **cmds = malloc(allocsize*sizeof(char*)); 
if (!cmds) { perror("malloc"); exit(EXIT_FAILURE); }; 

(順便說一句,經常檢查malloc結果;它可以失敗)。

,並避免realloc -ing每一次,我會以幾何方式增長分配的大小,所以內環路:

if (count>=allocsize) { 
    int newallocsize = (4*allocsize)/3+10; 
    cmds = realloc (cmds, newallocsize*sizeof(char*)); 
    if (!cmds) { perror("realloc"); exit(EXIT_FAILURE); }; 
    allocsize = newallocsize; 
} 

或者,而不是保持三個變量:cmdscountallocsize您可以使用一個以flexible array member結尾的單個struct(並保留其分配的和使用的尺寸)。

1
  • 第一個malloc是錯誤的..當你在* cmd之前取消了cmd,甚至在它被分配之前,你會得到什麼?
  • 它還使用的sizeof(char)的,這是不對的..

正確的方法是..

// strtok modifies the string. So use writable string 
char line[80] = "Hello my name is anand"; 
char *token = strtok(line, sep); 
int count = 0; 
// Alloc array of char* for total number of tokens we have right now 
char **cmds = (char **) malloc(sizeof(char*) * (count + 1)); 

while (token != NULL) 
{ 
    /** 
    * Alloc memory for the actual token to be stored.. 
    * token returned by strtok is just reference to the existing string 
    * in 'line' 
    */ 
    cmds[count] = malloc(sizeof(char) * ((strlen(token) + 1))); 
    // Adds tokens to array of delimited commands 
    strcpy(cmds[count], token); 
    count++; 

    token = strtok(NULL, sep); 
    if (token != NULL) 
    { 
     // resize array of tokens to store an extra token 
     char ** newCmds = (char **) realloc(cmds, sizeof(char*) * (count + 1)); 
     // only if realloc was successful then use it. 
     if (newCmds != NULL) 
     { 
      cmds = newCmds; 
     } 
    } 
}