2016-11-11 44 views
-1

我從std中讀取異常困難的時間,在空間上分割,然後將這些標記放入數組中。 (忽略的80個字節的分配,這是測試只是暫時的)在stdin上使用strtok時遇到問題

char* inputLine = (char*)malloc(80); 
char* commands[80]; 
char* input; 
int i; 
fgets(inputLine, 80, stdin); 
input = strtok(inputLine, " \n"); 
for (i=0; input != NULL; i++) { 
    memcpy(commands[i], input, sizeof(input)); 
    input = strtok(NULL, " \n"); 
} 

隨着

command1 command2 command3 

輸入輸出應該

commands[0] = "command1" 
commands[1] = "command2" 
commands[2] = "command3" 

然而,輸出我得到的是

commands[0] = "command1" 
commands[1] = "" 
commands[2] = "command3" 

在單步執行調試器時,可以看到命令[0]和命令[1]正確填充。但是,當最後一個memcpy被執行時,它會分配命令[2]並擦除命令[1]。

我對C的經驗非常有限,我感謝有人指出我的愚蠢錯誤!

+1

指針不是數組。你認爲'sizeof(input)'產生了什麼? – Olaf

回答

0

看來您還沒有分配內存來存儲命令。你只分配了一個指針數組,所以你的行爲實際上是未定義的。修復是分配內存並初始化它。

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

int main(){ 
    char* inputLine = (char*)malloc(80); 
    char* commands[80]; 
    char* input; 
    int i; 
    int numCommands = 0; 
    fgets(inputLine, 80, stdin); 
    input = strtok(inputLine, " \n"); 
    for (i=0; input != NULL; i++) { 
     numCommands++; 
     commands[i] = malloc(strlen(input) + 1); 
     strncpy(commands[i], input, strlen(input)); 
     input = strtok(NULL, " \n"); 
    } 

    for (i = 0; i < numCommands; i++) { 
     puts(commands[i]); 
    } 
} 
+0

爲了愛猴子,在分配內存時使用'strncpy()'和'strlen()'。 – Qix

+0

對不起,我會解決這個問題。我剛剛添加了相關的行。 – merlin2011

+0

謝謝你,我現在實際上是在修補手工內存管理,這就是原因。 – jlee

0

所以這裏是讀取標準輸入,並把它變成由空格分割令牌的arrary另一種解決方案:

int main(void) 
{ 
     char *line = NULL, *buf = NULL; 
     size_t len = 0; 
     size_t bufpos = 0, buflen = 0; 
     ssize_t bytes = 0; 
     char *p; 
     char **command = NULL; 
     size_t count = 0; 
     int k; 

     while((bytes = getline(&line, &len, stdin)) != -1) { 
       fprintf(stderr, "buf:%p, bufpos:%lu, buflen: %lu\n", buf, bufpos, buflen); 
       buflen += bytes; 
       buf = realloc(buf, buflen); 
       strncpy(buf+bufpos, line, bytes); 
       *(buf+bufpos+bytes-1) = ' '; /* change \n at the end to a space */ 
       bufpos = buflen; 
     } 

     free(line); 

     if(buflen == 0) { 
       exit(EXIT_FAILURE); 
     } 

     if(buf[buflen-1] == ' ') 
       buf[buflen-1] = 0; 

     command = malloc(sizeof(char *)); /* at least one command is there */ 

     /* mark all the commands */ 
     command[0] = buf; 
     count = 1; 
     for(p = buf; *p != 0; p++) { 
       int delimit = 0; 

       /* eatup consecutive whitespaces */ 
       while(isspace(*p)) { 
         delimit = 1; 
         *p = 0; 
         p++; 
         if(!*p || !isspace(*p)) 
           break; 
       } 

       if(delimit) { 
         command = realloc(command, (1+count)*sizeof(char *)); 
         command[count] = p; 

         count++; 
       } 
     } 

     for (k = 0; k < count; k++) { 
       fprintf(stdout, "%d : %s\n", k, command[k]); 
     } 

     free(command); 
     free(buf); 

     return 0; 
} 

有幾件事情需要注意:

  1. 這使用getline,這是一種非常安全的動態讀取字符串的方法。

  2. command數組是數組的指針指向到buf數組,它包含在閱讀一切的各個景點。這意味着,你不重新分配字符串所有的地方。您現在可以將buf傳遞給strtok,或者按照我在for循環中做的那樣分配和分配命令。

  3. 這對你如何界定commmands

  4. 您可以將此變成reenterant功能更多的控制。

0

您不需要分配太多內存。只要做到

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

int main() 
{ 
    char line[1024]; 

    while(fgets(line, sizeof line, stdin)) { 
     char *command[80]; 
     int n_command = 0, i; 
     char *p; 
     for (p = strtok(line, " \n"); p && (n_command < 80); p = strtok(NULL, " \n")) 
      command[n_command++] = p; 
     for (i = 0; i < n_command; i++) 
      printf("[%s]", command[i]); 
     puts(""); /* final end of line to stdout */ 
    } 
    return EXIT_SUCCESS; 
} /* main */ 

,你可以使用一個靜態的大小(足夠大的大線)和command條目的最大數量。請注意,當達到最多80個條目時,命令條目將被丟棄,並且如果線條較長,則每條線條損壞爲1024個字符。本示例僅在for循環中說明strtok(3)的使用。

$ pru_$$ | sed 's/^/ /' 
Lorem ipsum dolor sit amet sed. Arcu ac quam. Posuere malesuada in. Morbi et feugiat libero mauris pellentesque. Vulputate a vel et cupidatat mi mi. 

Praesent eget vestibulum mauris imperdiet et dolor aliquam dui. Ultrices donec nascetur. Ante neque hymenaeos. Quis sed placerat at ac et. Purus elementum vestibulum nunc. 

Et id eu tellus at libero enim odio et. Nec enim maecenas ac pellentesque magna placerat culpa ut. Dolor at malesuada justo est ut tellus sapien nunc. Diam saepe fermentum. Vivamus dolor adipiscing vitae wisi vivamus. Diam consequat lobortis. Integer habitasse feugiat. Non in minima. Lacus odio odio urna nunc. 
[Lorem] [ipsum] [dolor] [sit] [amet] [sed.] [Arcu] [ac] [quam.] [Posuere] [malesuada] [in.] [Morbi] [et] [feugiat] [libero] [mauris] [pellentesque.] [Vulputate] [a] [vel] [et] [cupidatat] [mi] [mi.] 

[Praesent] [eget] [vestibulum] [mauris] [imperdiet] [et] [dolor] [aliquam] [dui.] [Ultrices] [donec] [nascetur.] [Ante] [neque] [hymenaeos.] [Quis] [sed] [placerat] [at] [ac] [et.] [Purus] [elementum] [vestibulum] [nunc.] 

[Et] [id] [eu] [tellus] [at] [libero] [enim] [odio] [et.] [Nec] [enim] [maecenas] [ac] [pellentesque] [magna] [placerat] [culpa] [ut.] [Dolor] [at] [malesuada] [justo] [est] [ut] [tellus] [sapien] [nunc.] [Diam] [saepe] [fermentum.] [Vivamus] [dolor] [adipiscing] [vitae] [wisi] [vivamus.] [Diam] [consequat] [lobortis.] [Integer] [habitasse] [feugiat.] [Non] [in] [minima.] [Lacus] [odio] [odio] [urna] [nunc.]