【问题标题】:How to change the value of format specifier at runtime?如何在运行时更改格式说明符的值?
【发布时间】:2013-08-26 10:35:48
【问题描述】:

我在我的项目中使用 sscanf 将字符串从源缓冲区复制到目标缓冲区。 例如:

char* target;
target = (char*)malloc(100 * sizeof(char));
char* source = "Hello World";
sscanf(source, "%[^\t\n]", target); // trying to copy "Hello World" into target.
printf("%s\n", target);//this will print "Hello World".

但是这种编码方式是不被接受的。我的经理希望我做的事情是这样的:

sscanf(source, "%11[^\t\n]", target); // NOTE: I've written "%11". here, 11 == length of hello world.

也就是说,他希望我也提供格式说明符。 (在这种情况下为 %11)。

但是,问题在于源的长度可能不同,我不知道如何为每个不同长度的字符串编写正确的格式说明符。

【问题讨论】:

  • 你考虑过 strtok() 吗?
  • 控制字符串只是一个字符串。您可以计算字符数,然后组装适当的控制字符串。
  • Please don't cast the return value of malloc() in C。另外,不要使用sizeof (char),它总是1,只会增加混乱。
  • 我对C不太了解。加上字符串的大小有什么区别?
  • @Neil Kirk 如果我 grok 您的评论:在 "%11[^\t\n]" 中添加 "11" 会限制 char 的最大数量在target 作为source 可能比目的地的容量大得多。

标签: c++ c scanf format-specifiers


【解决方案1】:

要复制字符串,请使用strcpy()。它不分配空间,因此您也必须提供第二个缓冲区。还有strncpy(),它不会复制超过指定的字符。

如果你想一次性复制一个字符串,你可以使用strdup(),只是不要忘记之后释放内存。

【讨论】:

    【解决方案2】:

    首先,为此使用 strcpy()。

    其次,格式说明符只是一个字符串,所以在取到你想要的字符串的strlen()之后,用sprintf()就可以了。

    【讨论】:

      【解决方案3】:

      使用:

      sscanf(source, "%*[^\t\n]", maxlen, target)
      

      其中 maxlen 是您要读取的大小。

      似乎没有简单的方法可以使sscanf(或其任何兄弟)的格式字符串采用输入字符串的任意最大长度。该建议基于printfscanf 正交,但事实并非如此。

      您可能会发现使用strtokstrncpystrdup 复制令牌会更好。

      但是,既然它被标记为 C++,为什么不使用:

      std::stringstream ss(source);  
      std::string target;
      getline(ss, target, "\t");
      

      【讨论】:

      • 我用过这一行---> scanf(source, "%*[^\t\n]", maxlen, target);但它给了我垃圾价值。
      • 是的,这是不正确的——scanf() 在这方面与printf 不正交。它的意思是“跳过输入”,而不是“将输入值作为长度”。我实际上并不认为有 C 方式 [除了使用类似 sprintf 的东西来从中生成字符串]。我将编辑我的答案...
      • 我认为你的意思是“类比”而不是“正交”
      • @pelletjl:不,我在计算机科学中使用正交含义:en.wikipedia.org/wiki/Orthogonality#Computer_science
      【解决方案4】:

      使用target = strdup(source),或者如果仍然必须使用sscanf()

      动态创建格式。

      const char* source = "Hello World";
      size_t n = 10;  // See note below
      char* target;
      target = (char*) malloc(n);  // (char *) is needed for C++, but not C
      char format[1+20+5+1];
      sprintf(format, "%%" "%zu" "[^\t\n]", n - 1);
      sscanf(source, format, target); // trying to copy "Hello World" into target.
      printf("%s\n", source);//this will print "Hello World".
      printf("%s\n", target);//this will print "Hello Wor".
      

      您可能需要n = strlen(source) + 1,但上面说明了为scanf() 动态创建的格式说明符如何防止target 中的缓冲区溢出。

      【讨论】:

      • 最后一行是错误的。 scanf%s 在第一个空格处停止读取。
      • 一个迂腐的解决方案会将n == 1 处理为特例,因为"%0[^\t\n]" 是UB。
      猜你喜欢
      • 2019-12-08
      • 2018-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-01
      • 2016-02-13
      • 2013-08-28
      相关资源
      最近更新 更多