2012-07-18 159 views
2

With int snprintf(char *str, size_t size, const char *format, ...); 我可以寫入特定數量的字符到str如何從c字符串中讀取特定數量的字符?

如何從C字符串讀取特定數量的字符?

問候

+0

你是什麼意思的「從C字符串讀取」?如果你已經有字符串,你只需訪問數組(考慮nul終止符)並閱讀任何你想要的。 – sinelaw 2012-07-18 10:53:16

回答

6

您可以在格式參數傳遞一個數字:

char buf[21]; 
sscanf(str, "%20s", buf); 

這讀取多達20個字符到buf

如果你不知道你要多少數據在編譯時間閱讀,你可以在運行時編寫格式字符串:

char format[20]; 
sprintf(format, "%%%ds", howMuchToRead); 
sscanf(str, format, buf); 
+0

我們想出了同樣的解決方案:) +1 – betabandido 2012-07-18 10:56:23

+1

@betabandido嗯,這裏沒有太多的解決方案:) – dasblinkenlight 2012-07-18 10:57:29

+0

@dasblinkenlight:問題是,我得到一個變量'size_t howMuchToRead;'的形式。我可以將它與您的解決方案結合嗎? – ron 2012-07-18 10:57:38

2

您可以使用strncpymemcpy。但是,請注意,strncpy可能在某些情況下不會附加終止'\0'字符,並且該memcpy從來沒有。此外,memcpy根本不會檢查字符串的結尾,它只是複製您要求的字節數。

2

您可以使用sscanf

int sscanf(const char *str, const char *format, ...); 

例如:

char out[4]; 
sscanf("foo", "%3s", &out); 

當然,你也可以做一些更有趣的事情:

int value; 
sscanf("value=10", "value=%d", &value); 
2

sscanf,像scanf功能,是有問題的。隨着GNU手冊頁說:

必須有針對給定的格式說明足夠的地址參數;如果不是,結果是不可預測的,可能是災難性的。

所以有一個問題需要避免(編譯器無法驗證您是否傳遞了正確數量或類型的參數,儘管一些編譯器有一個專門針對這些函數警告您的黑客) 。這個問題的一部分還在於你需要對格式化字符串中的最大緩衝區大小進行硬編碼(這使得使用整數常量來防止緩衝區溢出變得更加困難)。由於你的用例僅僅是從一個字符串中複製一定數量的字符,所以我只是使用strncpy(並且一定要終止'\0'),正如Joachim Pileborg的回答所建議的那樣。對於長度參數,您應該使用輸入和輸出緩衝區的最小長度,減1以適應終止nul

換言之(未測試):

strncpy(dest, src, 
     MIN(NUM_OF_CHARS_TO_COPY, 
      MIN(DEST_BUFFER_SIZE, SRC_BUFFER_SIZE)) - 1); 

其中MIN(a,b)相當於a < b ? a : b上的整數。

3

替代既sscanfstrncpy解決方案,您還可以利用精度說明的(如"%.20s"只打印20個字符)。 C字符串的精度說明符已在this SO post中討論過。步驟與sscanf解決方案基本相同,您創建一個格式字符串&用它來捕獲所需的字符。
如果使用上述格式說明符(如"%20s"等),則使用sscanf,但如果字符串包含空格,則不保證您將獲得20個字符;如果遇到空格,那麼只有在空格之前纔會得到字符(因爲空格是scanf函數族的分隔符)。相反,你應該使用類似%20[^\n]的東西。 [^\n]表示直到換行符爲止,而20則指定要掃描的字符數。所有這些可以看出,在the following sample

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

int main(void) { 
     char format[20] = {0}; 
     char buf[50] = {0}; 
     char str[] = "Hello World! How are you?"; 
     size_t howMuchToRead = 8; 

     /* Using sscanf - till whitespace or size specified */ 
     snprintf(format, sizeof format, "%%%zus", howMuchToRead); 
     sscanf(str, format, buf); 
     printf("Using sscanf with %%8s format :%s\n", buf); 

     /* Using sscanf - read everything upto newline */ 
     snprintf(format, sizeof format, "%%%zu[^\n]", howMuchToRead); 
     sscanf(str, format, buf); 
     printf("Using sscanf with %%8[^\\n] format :%s\n", buf); 

     /* Using precision specifier */ 
     snprintf(format, sizeof format, "%%.%zus", howMuchToRead); 
     snprintf(buf, sizeof buf, format, str); 
     printf("Using precision specifier :%s\n", buf); 
     return 0; 
} 
/* 
Output: 
Using sscanf with %8s format :Hello 
Using sscanf with %8[^\n] format :Hello Wo 
Using precision specifier :Hello Wo 
*/ 

而且sinelaw's answer使你應該小心很重要的觀點。
希望這有助於!