【问题标题】:this code, its work fine and return what i want, but its hangs before print it?这段代码,它工作正常并返回我想要的,但它在打印之前挂起?
【发布时间】:2010-03-27 17:19:16
【问题描述】:

我制作了这个程序::

#include<stdio.h>

char *raw_input(char *msg);

main() {
char *s;
*s = *raw_input("Message Here Is: ");
printf("Return Done..");
printf(s);
}

char *raw_input(char *msg){
char *d;
    printf("%s", msg);
    scanf("%s",&d);
return d;
}

这是做什么的,它打印我的消息并扫描用户的输入,然后打印它,但是打印用户输入的问题是什么???

更新::

我需要 raw_input 函数。调用是这样的,没有任何额外的

*s = *raw_input("Message Here");

我不想用这个 ::

raw_input("Message Here Is: ", d);
....

只想返回用户将输入的字符串。

更新2::

来自 jamesdlin 的回答(谢谢),现在我很清楚,我的问题是如何在此返回分配的字符串 :)

#include<stdio.h>
#define buffer 128

char *raw_input(char *msg);

main() {
char *s;
s = raw_input("Message Here Is: ");
printf("%s\n",s);
}

char *raw_input(char *msg){
char *d;
    printf("%s", msg);
    fflush(stdout);
    fgets(d, buffer, stdin); ## In this there is a problem
return d;
}

现在,当我启动这个程序时,它会打印消息,然后退出(结束)程序而不从用户那里获取任何信息???

【问题讨论】:

    标签: c function pointers printf


    【解决方案1】:

    您没有为d 分配内存,因此在scanf 中使用它会导致未定义的行为。

    实际上,更糟糕的是:你将d地址 传递给scanf,然后用从控制台读取的整数填充。实际上,您使用整数值初始化指针,因此指针指向丛林中的某个地方。因此取消引用它是未定义的行为。 [更新]:即使这还不是全部:正如@Heath 在下面指出的那样,这实际上允许您通过在控制台上输入足够长的输入来破坏您的调用堆栈:-((( [/更新]

    更不用说你试图从你的函数中返回一个局部变量,一旦它超出范围就会被销毁。这应该会更好:

    void raw_input(char *msg, char *d);
    
    main() {
        char d[128];
    
        raw_input("Message Here Is: ", d);
        printf("Return Done..");
        printf(d);
    }
    
    void raw_input(char *msg, char *d){
        printf("%s", msg);
        scanf("%s", d);
    }
    

    很公平,这并不能防止缓冲区溢出……但足以说明我的观点。

    更新: 所以无论如何你都想从raw_input() 返回一个分配的字符串(即char* 指针)。 AFAIK 你有 3 个选择:

    • 返回一个由调用者作为参数传入的指针(我上面的例子的一个小扩展):这是我更喜欢的。但是,这需要一个额外的函数参数(实际上是 2,因为我们还应该在适当的解决方案中传递缓冲区的长度以避免缓冲区溢出)。所以如果你绝对需要坚持上面显示的函数签名,这不是一个选择。
    • 返回一个指向调用者和被调用者可见的静态/全局缓冲区的指针:这是上面的变体,以避免修改函数签名。缺点是代码更难理解和维护——你不知道函数修改了静态/全局变量而不实际查看它的实现。这反过来也使单元测试更加困难。
    • 返回指向函数内部分配的缓冲区的指针 - 虽然技术上可行,但这是最糟糕的选择,因为您有效地传递了缓冲区的所有权;换句话说,调用者必须记住释放返回的缓冲区。在像您上面展示的那个简单程序中,这似乎不是一个大问题,但在一个大程序中,该缓冲区可能会传递到应用程序中很远的地方,因此没有人释放它的风险很高最终导致内存泄漏。

    【讨论】:

    • 不,scanf 工作正常,如果我在 raw_input 中打印 d,但在主函数中,我会得到输出。它不起作用:)
    • 它可以正常工作,因为您的编译器恰好非常宽松,而且您很幸运。不能保证完全可以正常工作;您正在覆盖随机内存。
    • @Rami:彼得绝对正确。是什么让你的程序看起来可以工作(实际上,偶然发现)是你传递了 d 的地址,这会导致来自 scanf() 的输入字符串覆盖函数 raw_input 中的堆栈变量。您的函数 raw_input 永远不会返回。
    • 我想返回输入,但不使用指针返回它:)
    • @Heath Hunnicutt 很好的观察,我什至没有想到...但是,准确地说,只有当来自控制台的输入长于指针的大小时才会发生这种情况(通常为 4 个字节)。我猜@Rami 到目前为止只输入了较短的输入,这就是他还没有观察到堆栈损坏的原因。
    【解决方案2】:

    函数中的指针d未初始化。 scanf 将填满任意内存。相反,您需要传递一个缓冲区(字符数组)来填充,并且缓冲区必须在main 中定义,否则它将在您返回之前被销毁(除非您进行动态分配,但这是另一个故事)。

    【讨论】:

    • 您还需要花时间确保读取的最大字符数小于缓冲区的容量。
    【解决方案3】:
    #include<stdio.h>
    
    char *raw_input(char *msg);
    
    int main() {
        char *s;
        s = raw_input("Message Here Is: ");
        printf("Return Done..");
        printf("%s", s);
        free(s);
        return 0;
    }
    
    char *raw_input(char *msg){
        char *d;
            d = malloc(20)
            if(d==0) return 0;
            printf("%s", msg);
            scanf("%19s", d);
        return d;
    }
    

    试试这个,应该可以的。如我所见,其他答案指出了您的错误...我要放慢速度;)

    编辑:好的,发现一个错误...修复它;)

    编辑2: Max 建议可以使用结构,这里有一些代码:

    #include<stdio.h>
    
    struct mystring{
        char str[20];
    };
    
    struct mystring raw_input(char *msg);
    
    int main() {
        struct mystring input;
        input = raw_input("Message Here Is: ");
        printf("Return Done..");
        printf("%s", input.str);
        return 0;
    }
    
    struct mystring raw_input(char *msg){
        struct mystring input;
            printf("%s", msg);
            scanf("%19s", input.str);
        return input;
    }
    

    【讨论】:

    • 为什么投反对票?我是这个网站的新手,所以至少告诉我我做错了什么......谢谢。
    • 你不能在 C 中将字符串作为值返回,你必须使用指针。
    • @Genmutant:为什么不呢??为什么我不能返回一个字符串??
    • 如果你返回一个字符串,你必须返回一个指针。字符串只是一个以 0 结尾的字符数组。而且由于您不能将数组作为一个值返回,因此您不能将字符串作为值返回。在 C 中,您只能返回 一个 值,在这种情况下,您必须返回指向字符串第一个字符的指针。
    • 嗯,你可以返回一个包含数组的结构体。
    【解决方案4】:

    如前所述,您没有分配用于scanf 的内存。但永远不要使用scanf;很难正确使用并避免缓冲区溢出。使用fgets

    来自 comp.lang.c 常见问题解答:Why does everyone say not to use scanf? What should I use instead?

    另外,虽然与您的问题无关,但这段代码很危险:

    *s = *raw_input("Message Here Is: ");
    printf("Return Done..");
    printf(s);
    

    您将用户输入作为格式字符串直接传递给printf,因此如果打印的字符串恰好包含% 字符,这很容易受到格式字符串攻击。更好:

    *s = *raw_input("Message Here Is: ");
    printf("Return Done..");
    printf("%s\n", s);
    

    另外,打印时您可能需要一些换行符。另外:

    *s = *raw_input("Message Here Is: ");
    

    不起作用,因为s 没有指向任何东西,所以你取消引用一个垃圾指针。假设您修复raw_input 以返回分配的字符串,它应该是:

    s = raw_input("Message Here Is: ");
    

    最后(也与您的问题无关):

    char *raw_input(char *msg){
        char *d;
        printf("%s", msg);
        scanf("%s",&d);
        return d;
    }
    

    您应该在打印提示后调用fflush(stdout)。见My program's prompts and intermediate output don't always show up on the screen, especially when I pipe the output through another program.

    【讨论】:

    • 但是如何返回分配的字符串,这正是我想要的??
    【解决方案5】:

    试试这个实验:

    #include<stdio.h>
    
    char *raw_input(char *msg);
    
    main() {
        char *s;
        s = raw_input("Message Here Is: ");
        printf("Return Done..");
        printf(s);
    }
    
    char *raw_input(char *msg)
    {
        int value = 0;
        char *d;
        printf("%s", msg);
        scanf("%s",&d);
    
        if (value)
            printf("value has become %08X\n", value);
        return d;
    }
    

    使用输入消息执行多个实验,只要:3、4、5、7、8、9、11、12、13 等字符长。查看整数变量value 的结果。您会看到,由于您通过传递d 的地址来滥用scanf(),因此您允许scanf() 破坏您的函数的局部变量,包括返回地址。

    这让我们回到了这个网站的名称。

    【讨论】:

    • 它不像其他代码那样工作,它只是在打印输出时停止工作,我不知道是什么问题??
    • 它不应该工作。它应该向您展示您从键盘输入的内容以某种方式成为变量“值”的一部分。
    • 它甚至不打印值,它只是从键盘获取字符串然后停止工作!!??
    【解决方案6】:

    您不能返回在函数内部创建的变量的指针。变量 d 在主函数中不再有效。

    试试这个: 1.在main函数中创建变量d 2. 并将其传递给 raw_input 函数

    void raw_input(char *msg, char *d)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-02
      • 2021-08-02
      • 2014-10-07
      • 2020-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-06
      相关资源
      最近更新 更多