2016-10-31 30 views
1

我是C的初學者,請不要打擾我。 所以,我有這個功能得到一個「IP /掩碼」字符串類型的面膜:如何分割沒有strtok的字符串?

char *getmask(char n[]) { 
    char x[255] = { 0 }; 
    strcpy(x, n); 
    char *mask; 
    mask = strtok(x, "/"); 
    mask = strtok(NULL, "/"); 
    return mask; 
} 

的問題是,我需要做的是在多個「IP /掩碼」這都在一個串。所以,當我這樣做:

net = strtok(x4, " "); 
net = strtok(NULL, " "); 
while (net != NULL) { 
    net = strtok(NULL, " "); 
    strcpy(masca, "\n"); 
    strcpy(masca, getmask(net)); 
    //some other code 
} 

的問題是,strtok()故障,因爲我把它起初的一段時間,但隨後它得到getmask(net)再次調用。

無論如何繞過它?如果不是,我還能如何分割一個字符串?

+0

你是以'net = strtok(NULL,「」)'開始的嗎?問題描述很混亂。用輸入和輸出顯示最小程序。 –

+0

對不起,第一個strtok是在此之前。我將編輯 – Andrei

+0

'strtok'作爲狀態機運行,所以每個呼叫都有狀態。爲了分割一系列空格分隔的令牌和'/'分隔的令牌的子集,您需要防止狀態發生衝突。這可以通過迭代兩次完成,或者如@Ludonope – Aaron3468

回答

2

使用strtok_r()。這與strtok的行爲相同,但允許您「同時」處理多個字符串。

char *strtok_r(char *str, const char *delim, char **saveptr); 

的strtok_r()函數是一個可重入版本的strtok()。 saveptr參數是指向由strtok_r()內部使用的char *變量的指針,以便在解析相同字符串的連續調用之間維護上下文。

第一次調用strtok_r()時,str應該指向要解析的字符串,而saveptr的值將被忽略。在隨後的調用中,str應該爲NULL,並且自上一次調用以來saveptr應該保持不變。

可以使用指定不同saveptr參數的strtok_r()調用序列同時分析不同的字符串。

來源:Linux手冊strtok_r

+0

恐怕使用'strtok_r()',它可能在OP的系統上不可用,它不會修正getmask()中的明顯缺陷:將指針返回到本地數組'x'會導致未定義的行爲。 – chqrlie

+0

嘗試編寫一個類似的函數,它需要一些字符串操作,但這不是很難:) – Ludonope

0

你的函數調用getmask()未定義行爲:

  • 複製字符串參數轉換爲本地陣列x;
  • 你用strtok()解析它,它返回一個指針到同一個本地數組x
  • 您將此指針mask返回給調用者。一旦退出此功能,該指針就會失效。

您應該返回一個指向該數組的分配副本的指針,以便在返回到調用方後它仍然有效。

此外,你應該避免使用strtok(),因爲它不是可重入的:正如你注意到的,你不能用這個函數實現嵌套的解析器。

其他功能都可以解析字符串:

  • strchr()座落在一個字符串的字符;
  • strstr()查找字符串中的子字符串;
  • strspn()匹配字符串開頭的一組字符;
  • strcspn()匹配字符串開頭的一組字符的補碼;
  • 您還可以手動解析字符串,測試循環中的字符。

下面是一個例子:

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

char *getmask(const char *s) { 
    /* allocate a copy of the mask part 
    * the mask starts after the first '/' 
    * and stops at the first space or another '/' 
    */ 
    len - 0; 
    s = strchr(s, '/'); 
    if (s != NULL) { 
     s++; 
     len = strcspn(s, "/ \t\r\n"); 
    } 
    /* allocate space for the mask string */ 
    char *mask = malloc(len + 1); 
    if (mask != NULL) { 
     /* copy the mask string */ 
     memcpy(mask, s, len); 
     mask[len] = '\0'; 
    } 
    return mask; 
} 

功能是麻煩的,但非常精確。它的行爲幾乎與strtok()所預期的相同,唯一的區別是處理多個連續的/字節,其中strtok()會跳過,而strchr()不會。

這裏是sscanf()替代:

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

char *getmask(const char *s) { 
    char mask[256]; 
    /* skip characters different from /, then skip slashes, then 
    * copy characters until another/or whitespace 
    */ 
    if (sscanf(s, "%*[^/]%*[/]%255[^/ \t\n]", mask) != 1) { 
     *mask = '\0'; 
    } 
    return strdup(mask); /* POSIX function to allocate a copy of a string */ 
} 

這是很簡單的,但如果字符串以/啓動失敗。

strdup()是一個非常有用的函數來分配一個字符串的副本。它在POSIX兼容系統上可用。這你不用它,它可以能夠很容易地實現:通過getmask()分配應被釋放

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

char *strdup(const char *s) { 
    char *p = malloc(strlen(s)); 
    if (p != NULL) { 
     strcpy(p, s); 
    } 
    return p; 
} 

字符串由free()當不再需要。

在調用getmask()之前,可以使用類似的方法將輸入字符串解析爲ip/mask地址對。

你也可以提供一個目標緩衝區,以getmask()以避免內存管理的複雜性:

char *getmask(char *dest, size_t size, const char *s) { 
    if (dest != NULL && size > 0) { 
     char mask[256]; 
     /* skip characters different from /, then skip slashes, then 
     * copy characters until another/or whitespace 
     * dest cannot be used directly because size cannot be passed 
     * sscanf easily 
     */ 
     *dest = '\0'; 
     if (sscanf(s, "%*[^/]%*[/]%255[^/ \t\n]", mask) != 1) { 
      strncat(dest, mask, size - 1); 
     } 
    } 
    return dest; 
} 

解析是棘手,因爲你必須要小心處理所有案件。規範通常不夠精確,所以實施者必須針對特殊情況做出選擇。 C庫提供的用於解析的工具老舊笨重,特別是strtok(),sscanf()。使用這些時要小心,即使是有經驗的程序員也會因其副作用和缺點而被咬傷。