2017-09-23 69 views
0

sscanf是這樣工作的:sscanf是否有指向輸入字符串而不是緩衝區的指針?

int main(const int argc, const char *argv[]) { 
    char buf1[1024] = {0}; 
    char buf2[1024] = {0}; 
    char buf3[1024] = {0}; 
    char *str = "abc, 123; xyz"; 
    sscanf(str, "%[^,], %[^;]; %s", buf1, buf2, buf3); 
    printf("'%s' '%s' '%s'", buf1, buf2, buf3); // Prints: "'abc' '123' 'xyz'" 
    return 0; 
} 

我想知道是否有不需要複製的str內容到緩衝區(buf1, buf2, buf3),也沒有分配任何新的記憶功能。相反,它只會將指針(ptr1, ptr2, ptr3)設置爲指向str中的匹配部分,並且在匹配之後將null結束。

int main(const int argc, const char *argv[]) { 
    char *ptr1 = NULL; 
    char *ptr2 = NULL; 
    char *ptr3 = NULL; 
    char *str = "abc, 123; xyz"; 
    // 
    // str = "abc, 123; xyz\0" 
    // 
    _sscanf(str, "%[^,], %[^;]; %s", &ptr1, &ptr2, &ptr3); 
    // 
    // str = "abc\0 123\0 xyz\0" 
    //  ^ ^ ^
    //  ptr1 ptr2 ptr3 
    // 
    printf("'%s' '%s' '%s'", ptr1, ptr2, ptr3); // Prints: "'abc' '123' 'xyz'" 

    return 0; 
} 

我知道有作爲strtok_r功能,以及regex.h庫,也可以使用,但我認爲這將是在輸入字符串可以被修改的情況下更方便。

+0

的問題是,'sscanf'解析的輸入不能始終* *是空終止的! 'regex.h'返回子組匹配的*範圍*,這是可行的。 –

+0

你的問題是一個廢話,就好像你null終止原始字符串中間的某個地方一樣,你將永遠不會再是同一個字符串str,因爲即使你移動了其餘的字符,如果正確的str的大小增加和最有可能的重新分配將需要 –

+0

請注意,我在某些情況下說。在某些情況下,我不關心輸入字符串是否被修改。 –

回答

4

它並不漂亮,但%n說明符可能用於捕獲標記開始和結束的索引。錯誤檢查將確保指數和最終值不-1

#include <stdio.h> 

int main(int argc, char *argv[]) { 
    int index1 = -1; 
    int end1 = -1; 
    int index2 = -1; 
    int end2 = -1; 
    int index3 = -1; 
    int end3 = -1; 
    char *str = "abc, 123; xyz"; 
    sscanf(str, " %n%*[^,]%n, %n%*[^;]%n; %n%*s%n", &index1, &end1, &index2, &end2, &index3, &end3); 
    printf("'%.*s' '%.*s' '%.*s'", end1, str + index1, end2 - index2, str + index2, end3 - index3, str + index3); // Prints: "'abc' '123' 'xyz'" 
    return 0; 
} 
1

沒有與指針最終以char *指向在原始的字符串位置標準化的變種。在POSIX中有一個變體爲每個字符串項分配內存並將其複製到每個字符串項。

sscanf()的功能與fscanf()和其他變體的功能相匹配,並且在非常廣泛的範圍內,適用於所有變體的變體適用於所有變體。但是,您正在尋找的內容不能應用於基於文件的變體,因此它不存在。


有一個sscanf()的變種,爲字符串分配內存。這是POSIX 2008變體sscanf()m修改器。

[CX]⌦的%c%s,和%[轉換說明應接受一個可選的分配分配字符「M」,其中應導致分配存儲器緩衝器來保存串並轉換,包括終止空字符。在這種情況下,與轉換說明符對應的參數應該是對指針變量的引用,該變量將接收指向已分配緩衝區的指針。系統將分配一個緩衝區,就好像malloc()已被調用一樣。應用程序應負責在使用後釋放內存。如果沒有足夠的內存分配緩衝區,則該功能應將errno設置爲[ENOMEM],並導致轉換錯誤。如果函數返回EOF,則在函數返回之前,將使用由此調用成功分配給使用分配分配字符'm'的參數的任何內存。 ⌫

的[CX]符號標記此作爲擴展在C標準(所以m改性劑是不標準C的一部分,並且它不到處支持),並且⌦和⌫符號標記範圍的擴展名。因此,如果您的實現支持它(例如,Linux不支持,macOS Sierra則不支持),則會有sscanf()的變化,它會爲您分配正確大小的緩衝區,並且需要參數char **

在Linux手冊頁說:

一個可選的 'M' 字。這與字符串轉換(%s,%c,%[)一起使用,並且減輕了調用者需要分配相應的緩衝區以容納輸入:scanf()而是分配足夠大小的緩衝區,並且將該緩衝區的地址分配給相應的指針參數,它應該是指向變量char *的指針(該變量在調用之前不需要初始化)。當不再需要時,調用者應隨後釋放(3)該緩衝區。

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

int main(void) 
{ 
    char data[] = "The hills are alive with the sound of music"; 
    char *w[9]; 

    if (sscanf(data, "%ms %ms %ms %ms %ms %ms %ms %ms %ms", 
       &w[0], &w[1], &w[2], &w[3], &w[4], &w[5], &w[6], &w[7], &w[8]) != 9) 
    { 
     fprintf(stderr, "Oops!\n"); 
     return 1; 
    } 
    printf("Forwards: %s\n", data); 
    printf("Reversed:"); 
    for (int i = 8; i >= 0; i--) 
     printf(" %s", w[i]); 
    putchar('\n'); 
    for (int i = 0; i < 9; i++) 
     free(w[i]); 
    return 0; 
} 

輸出:

Forwards: The hills are alive with the sound of music 
Reversed: music of sound the with alive are hills The 
+0

雖然這仍然會複製字符串。它不返回指向輸入字符串的指針,這是OP要求的, – zwol

+0

@zwol:哦,我第一次誤解了這個問題。我相應地修改了我的答案。 –

+0

'm'修飾符也適用於Posix'scanf'和'fscanf'。 (我知道你知道這一點,但我認爲你的答案可能會被誤解。) – rici

相關問題