这段代码,它的工作正常并返回我想要的东西,但它在打印之前挂起了吗?

时间:2010-03-27 17:19:17

标签: c function pointers printf

我制作这个节目::

#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);
....

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

UPDATE2 ::

来自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;
}

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

6 个答案:

答案 0 :(得分:5)

您没有为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);
}

足够公平,这并不能阻止缓冲区溢出......但这足以说明我的观点。

更新:,因此您希望在任何情况下都从char*返回已分配的字符串(即raw_input()指针)。 AFAIK你有3个选择:

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

答案 1 :(得分:2)

函数中的指针d未初始化。 scanf将填补任意记忆。相反,你需要传递一个缓冲区(字符数组)来填充它,缓冲区必须在main中定义,否则它会在你返回它之前被销毁(除非你做动态分配,但是那是另一个故事。)

答案 2 :(得分:2)

#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;
}

试试这个,应该有效。其他答案指出你的错误,我可以看到......我要慢;)

编辑:好的,发现错误......修好了;)

EDIT2: 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;
}

答案 3 :(得分:2)

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

来自comp.lang.c FAQ: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.

答案 4 :(得分:1)

尝试此实验:

#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的结果。您将看到由于您通过传递scanf()的地址而误用d,您允许scanf()销毁函数的局部变量,包括返回地址。

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

答案 5 :(得分:0)

您无法返回已在函数内创建的变量的指针。变量d在main函数中不再有效。

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

void raw_input(char *msg, char *d)