【问题标题】:scanf dynamic allocationscanf动态分配
【发布时间】:2012-08-09 05:51:51
【问题描述】:

无论出于何种原因,都会打印以下代码(null):

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

int main(void)
{
    char *foo; 
    scanf("%ms", &foo);
    printf("%s", foo);
    free(foo);
}

我正在尝试为字符串动态分配内存,但正如我之前所说,我的程序只是输出 (null)。我通过使用 getche 和 realloc 创建一个函数来解决这个问题,但这似乎几乎毫无意义,因为我还必须编写如果用户输入退格、制表符等会发生什么。但正如我所说,这只是一项工作周围,​​我宁愿知道为什么上面的代码不起作用......

附加信息:

我正在使用 Pelles C IDE v7.00 并使用 C11 标准进行编译

【问题讨论】:

  • 这是不标准的吗?我在我的 scanf 文档中没有看到这一点。
  • 我在我的 C11 副本中没有看到任何关于 m 标志的信息(诚然,这是一个草稿)。你在哪里得到它?在我看来,它主要是 GCC 特定的东西,你不太可能在任何其他库实现中都找不到。
  • gcc.gnu.org/ml/gcc-patches/2007-09/msg01342.html 也许我的编译器不支持?在 C99 中有 a 标志我认为 m 标志是根据本文档的新版本
  • m 标志现在在 POSIX 中,在 2008 版中添加。标准的好处...
  • @Palec scanf("%ms", &amp;foo); 是正确的。 %ms 说明符分配内存并“返回”指向该内存的指针。 foo 的初始值未使用。

标签: c string dynamic input


【解决方案1】:

scanf/sscanf 的手册页中有一个示例(第 3 页,第 270-290 行),说明如下:

示例

要使用动态分配转换说明符,请将 m 指定为长度修饰符(因此为 %ms 或 %m[range])。调用者必须释放(3)返回的字符串,如下例所示:

char *p;
int n;

errno = 0;
n = scanf("%m[a-z]", &p);
if (n == 1) {
   printf("read: %s\n", p);
   free(p);
} else if (errno != 0) {
   perror("scanf");
} else {
   fprintf(stderr, "No matching characters\n");
}

如上例所示,只有在scanf()调用成功读取字符串时才需要调用free(3)。

来源:SCANF(3) - Linux 程序员手册 - GNU - 2013-01-30

【讨论】:

    【解决方案2】:

    %m 是一个 POSIX 扩展,这可能是它在 Pelles C 中不可用的原因。

    【讨论】:

      【解决方案3】:

      正如Arun 所说,这个解决方案是正确的,Meninx 的意见是错误的:

      char *s;
      scanf("%ms", &s);
      printf("%s", s);
      free(s);
      

      我读过'man scanf',上面写着:

      可选的“m”字符。这用于字符串转换(%s, %c, %[),
      并减轻调用者分配相应缓冲区的需要 保留输入:相反,scanf() 分配了一个足够大的缓冲区,并且 将此缓冲区的地址分配给相应的指针 参数,它应该是一个指向 char * 变量的指针(这个变量 调用前不需要初始化)。调用者应该 随后在不再需要此缓冲区时释放(3)此缓冲区。

      【讨论】:

        【解决方案4】:

        我正在使用带有 gcc 4.7.2 的 Linux 3.2.0 amd 64。使用代码:

        char *s; 
        scanf("%ms", &s);
        printf("%s", s);
        free(s);
        

        工作正常,但它不接受空格。

        对于静态分配,您可以改用:

        char s[100];
        printf("Enter string (max 99 characters): ");
        scanf("%100[^\n]s", &s);
        printf("You entered: %s\n", s);
        

        希望对你有帮助!

        【讨论】:

        • 很抱歉,但您并没有帮助他,因为如果您查看您的scanf() 功能,您肯定会意识到这是错误的!它应该是scanf("%ms", s),因为 s 本身就是一个指针!请注意s 之前没有&amp;。此外请记住,如果有的话,它不适用于程序中的下一个scanf!希望清楚!!!
        • @Meninx:不,%ms,应该是scanf("%ms", &amp;s)。 POSIX m 扩展为您分配字符串并将其分配给s,其类型必须为char*
        • scanf("%ms", &amp;s) 是正确的,调用修改了存储在s 中的指针。但是,scanf("%100[^\n]s", &amp;s) 是错误的。它必须是scanf("%99[^\n]", s)。在这种情况下,指向缓冲区第一个字节的指针需要按值传递,所以s是正确的。而右括号] 之后的s 是错误的,它不是转换的一部分。但是,最重要的是,缓冲区必须比字段宽度长,以便为终止的空字节留出空间。 对 100 字节缓冲区使用 100 的字段宽度允许用户超出缓冲区
        【解决方案5】:

        我在Draft C11 standardfscanf 的部分)的第 7.21.6.2 节中没有看到 %m。我建议您避免使用它并像在 C99 中那样调用 malloc()

        【讨论】:

        • 鉴于您无法预测使用scanf("%s") 分配多少空间,我还建议完全避免使用scanf 并使用fgetssscanf
        • %ms 表示法是scanf() 中的POSIX 扩展,与scanf() 的标准C 版本相比。
        • 也许将它与告诉您数据有多大的方法结合使用,您提前收到(在堆栈上)。只是一个想法。
        猜你喜欢
        • 2020-04-21
        • 1970-01-01
        • 1970-01-01
        • 2010-12-04
        • 2020-12-05
        • 2019-06-25
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多