2010-12-21 57 views
2

line被fgets'd,並且在while循環用計數器n運行,d是具有2個字符數組,pq一個結構。基本上,用幾句話來說,我想讀一條線,將它分成兩個字符串,一個直到第一個空格,另一個與剩下的一行。之後我清理(\n從文件變爲\'0')。代碼的工作原理,但有沒有更習慣於這樣做的方式?我在「不知情」中遇到什麼錯誤?讀取一條線,標記化和分配給STRUCT用C

size_t spc = strcspn(line," "); 
    strncpy(d[n].p, line, spc); 
    d[n].p[spc+1]='\0'; 
    size_t l = strlen(line)-spc; 
    strncpy(d[n].q, line+spc+1, l); 
    char* nl = strchr(d[n].q, '\n'); 
    if(nl){ 
     *nl='\0'; 
    } 
    n++; 

編輯q可能會包含空格。

謝謝。

+1

`strcspn`和`strlen`回報`size_t`,不`int`。在這裏使用錯誤的類型在99%時間內是無害的,但這是一個壞習慣,因爲偶爾會導致漏洞。 – 2010-12-21 20:38:21

+0

@R:固定。還有「5」。 – 2010-12-22 01:17:03

回答

1

我會寫很接近你的代碼。一些調整:

  • 你不會得到任何東西出來的strncpy這裏,使用memcpy
  • 您從strcspn中得不到任何東西,請使用strchr
  • 避免掃描部分字符串兩次。

所以:

char *spc = strchr(line, ' '); 
memcpy(d[n].p, line, spc - line); 
d[n].p[spc - line] = '\0'; 

spc++; 
char *end = strchr(spc, '\n'); 
if (end) 
{ 
    memcpy(d[n].q, spc, end - spc); 
    d[n].q[end - spc] = '\0'; 
} 
else 
    strcpy(d[n].q, spc); 

n++; 
1

你總是可以使用:

sscanf(line, "%s %s", d[n].p, d[n].q); 

假設你想投入p和q不包含空格的東西,而p和q是保證大到足以容納令牌包括零終止。

scanf函數是危險的,但正確使用時非常有用。

+0

然後檢查scanf手冊頁,您需要一個稍微更復雜的模式來匹配而不是最後的%s。 – harald 2010-12-21 20:04:31

+0

格式字符串中的空格將被忽略,「%s%s」等同於「%s%s」 – user411313 2010-12-21 22:14:17

1
scanf("%s %[^\n]", d[n].p, d[n].q); 

%[...]指令就像%s,但不是匹配的非空白,它的括號內的字符匹配 - 或所有字符,除了那些在括號內,如果^是領先的。

您應該檢查返回值以確定q是否實際輸入;如果「其餘行」實際上是空的,則它的行爲與您的代碼有所不同。 (或者如果行以空格開頭)

2

這可以用純指針算術來完成。假設line包含當前行:

char *p = line; 
char *part1, *part2; 

while (*p && *p != ' ') { 
    p++; 
} 

if (*p == ' ') { 
    *p++ = '\0'; 
    part1 = strdup(line); 
    part2 = strdup(p); 

    if (!part1 || !part2) { 
    /* insufficient memory */ 
    } 
} else { 
    /* line doesn't contain a space */ 
} 

基本上你掃描字符串,直到一個空間中第一次出現,然後替換爲空字符的空間來指示第一部分結束(strdup需要知道在哪裏停止),然後將指針前進一個以獲取字符串的其餘部分。

爲了使代碼看起來更乾淨,但與調用函數的開銷,你可以使用strchr(),而不是while循環:

char *p = strchr(line, ' '); 
char *part1, *part2; 

if (p) { 
    *p++ = '\0'; 
    part1 = strdup(line); 
    part2 = strdup(p); 
}