使用 sscanf 读取字符串

kat*_*ata 5 c input scanf

我正在尝试将 1 个字符和 2 个字符串保存到变量中。我使用 sscanf 读取以下形式的字符串:

N "OldName" "NewName"
Run Code Online (Sandbox Code Playgroud)

我想要的: char character = 'N', char* old_name = "OldName", char* new_name = "NewName"

这就是我尝试这样做的方式:

sscanf(mystring,"%c %s %s",&character,old_name,new_name);
printf("%c %s %s",character,old_name,new_name);
Run Code Online (Sandbox Code Playgroud)

问题是,我的问题在没有任何输出的情况下停止工作。(我也想忽略引号并只保存其内容)

Som*_*ude 5

当你这样做时

char* new_name = "NewName";
Run Code Online (Sandbox Code Playgroud)

您使指针new_name指向包含常量字符串文字的只读字符串数组。该数组恰好包含 8 个字符(字符串的字母加上终止符)。

首先,使用该指针作为 for 的目标scanf将导致scanf写入只读数组,从而导致未定义的行为。如果你给出的字符串超过 7 个字符,那么scanf也会尝试越界写入,再次导致未定义的行为

简单的解决方案是使用实际的数组,而不是指针,并且还告诉scanf不要读取超出数组容量的内容。像这样:

char old_name[64];  // Space for 63 characters plus string terminator
char new_name[64];

sscanf(mystring,"%c %63s %63s",&character,old_name,new_name);
Run Code Online (Sandbox Code Playgroud)

要跳过引号,您有多种选择:使用指针和指针算术来跳过前导引号,然后在最后一个引号的位置设置字符串终止符以“删除”它。另一种解决方案是移动字符串以覆盖前导引号,然后按照之前的解决方案删除最后一个引号。

或者您可以依赖(和系列)的有限模式匹配功能:scanf

sscanf(mystring,"%c \"%63s\" \"%63s\"",&character,old_name,new_name);
Run Code Online (Sandbox Code Playgroud)

请注意,如果字符串实际上包含引号,则上述sscanf调用将起作用。

第二个注意事项:正如 Cool Guy 的评论中所说,上述内容实际上不会起作用,因为scanf贪婪。它将读取直到文件/字符串末尾或空格,因此它实际上不会在结束双引号处停止读取。使用 and family 的唯一有效解决方案scanf是下面的解决方案。

还要注意的是scanf,当读取字符串时,使用"%s"停止读取空白,所以如果字符串是"New Name"那么它也不起作用。如果是这种情况,那么您要么需要手动解析字符串,要么使用奇怪的"%["格式,例如

sscanf(mystring,"%c \"%63[^\"]\" \"%63[^\"]\"",&character,old_name,new_name);
Run Code Online (Sandbox Code Playgroud)