【问题标题】:scanf() variable length specifierscanf() 可变长度说明符
【发布时间】:2014-08-20 17:13:47
【问题描述】:

如何使用变量指定scanf() 应读取的最大字符数?

例如使用printf(),你可以像这样使用*

#define MAXVAL 5
printf("Print at maximum MAXVAL chars: %.*s\n", MAXVAL, "myStringHere");

这只会打印 5 个字符,我怎样才能让 scanf 只在 MAXVAL 中读取? MAXVAL 必须用作长度说明符。我不能干脆做

scanf("%5s", string);

现在我只能想到使用scanf 读入一个大数组,然后使用ssprintf 将字符串存储到我的长度有限的字符串中。但是,使用长度说明符会容易得多。

【问题讨论】:

  • -1 的大小减少了这个数量,因为scanf 为该字符串添加了一个 NUL 字符读取 (%s)。例如。 scanf("%4s", string);
  • @user3121023 我想他想使用MAXVAL,而不是在格式字符串中硬编码一个值。
  • @mafso fgets 换行符,scanf 空白符。 @CSSStudent 您可以在代码中创建格式说明符。
  • @FilipeGonçalves 你说得对,我需要使用MAXVAL
  • @clcto "scanf break on whitespace" 忽略格式参数的影响。函数scanf() 不一定会在空白处中断,因为它取决于格式。 scanf("%5s") 将消耗前导空白(不会在 w-s 上中断),然后扫描非空白字符直到 1) 空白(在 w-s 上中断)2) 5 char 读取 3) EOF 或 4) IOError .

标签: c scanf


【解决方案1】:

您可以使用 C 预处理器来帮助您。

#define STR2(x) #x
#define STR(X) STR2(X)
scanf("%" STR(MAXVAL) "s", string);

处理器将"%" STR(MAXVAL) "s" 结合到"%5s"

【讨论】:

  • 这是一个非常聪明的方法。预处理器的有趣使用
  • 我刚试过这个方法,用2#defines有什么需要?我不能只使用#define STR(x) #x 然后使用scanf("%" STR(MAXVAL) "s", string); 吗?
  • 通读该问题的答案后,我仍然感到困惑。我不明白为什么需要 2 defines。我错过了什么明显的东西吗?
  • @CSSStudent:这两个定义是必要的,以便正确扩展参数。也就是说,如果STR(X) 被简单地定义为#x,那么STR(MAXVAL) 将扩展为#MAXVAL,这意味着scanf 调用将扩展为scanf("%" "MAXVAL" "s", string );,这不是您想要的。通过使用第二个定义,MAXVAL 将在被字符串化之前扩展为 5。
【解决方案2】:
#include <stdio.h>

#define MAXLEN 5
#define S_(x) #x
#define S(x) S_(x)

int main(void){
    char string[MAXLEN+1];

    scanf("%" S(MAXLEN) "s", string);
    printf("<%.*s>\n", MAXLEN, string);
    return 0;
}

【讨论】:

    【解决方案3】:

    Kernighan and Pike 建议使用 snprintf() 创建格式字符串。 我把这个想法发展成一种可以安全读取字符串的方法:

    void scan_string(char * buffer, unsigned length) {
        char format[12]; // Support max int value for the format %<num>s
        snprintf(format, sizeof(format), "%%%ds", length - 1); // Generate format
        scanf(format, buffer);
    }
    
    int main() {
      char string[5];
      scan_string(string, sizeof(string));
      printf("%s\n", string);
    }
    

    【讨论】:

      【解决方案4】:

      你不能。您需要使用scanf() 以外的其他内容。一个不错的流行选择是 fgets(),尽管它的语义略有不同:fgets() 将读取一行输入,而 scanf()%s 将读取空格分隔的字符序列。

      要使用fgets(),您需要类似:

      fgets(string, MAXVAL, stdin);
      

      如果出于某种原因您真的想使用scanf(),请查看以下问题:How to prevent scanf causing a buffer overflow in C?

      【讨论】:

      • 这可能是保持良好可读性的最佳选择,但我想我会使用预处理器的诡计。所以我仍然可以使用scanf()
      猜你喜欢
      • 2013-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多