views:

179

answers:

6

I make this program ::

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

What this do is, it print my message and scan for input from the user, then print it,, but whats the problem in print the input from the user ???

Update::

I need the raw_input func. call be like this without any extra

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

I dont want to use this ::

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

Just want to return the string that the user will enter .

Update2::

from jamesdlin Answer( Thank You ),,Now its clear to my that's my problem was in how to return an allocated string in this :)

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

now when i start this program its print the message and then just exit(end)the program without taking any word from the user ???

+5  A: 

You don't allocate memory for d, so using it in scanf leads to undefined behaviour.

Actually, it's even worse than that: you pass the address of d to scanf, which is then filled with the integer read from console. In effect, you initialize a pointer with an integer value, so the pointer points to somewhere out in the jungle. Thus dereferencing it is undefined behaviour. [Update]: even this is not all: as @Heath pointed out below, this in fact allows you to corrupt your call stack by entering a sufficiently long input on the console :-((( [/Update]

Not to mention that you are trying to return a local variable from your function, which is destroyed as soon as it gets out of scope. This should work better:

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

Fair enough, this does not prevent buffer overflow... but it is enough to ilustrate my point.

Update: so you want to return an allocated string (i.e. a char* pointer) from raw_input() in any case. AFAIK you have 3 choices:

  • return a pointer passed in by the caller as a parameter (a slight extension of my example above): this is the one I would prefer. However, this requires an extra function parameter (in fact 2, since we should also pass in the length of the buffer in a proper solution to avoid buffer overflows). So if you absolutely need to stick to the function signature shown above, this isn't an option.
  • return a pointer to a static / global buffer visible to both caller and callee: this is a variation of the above, to avoid modifying the function signature. The downside is that the code is more difficult to understand and maintain - you don't know that the function modifies a static / global variable without actually looking at its implementation. This in turn also makes unit testing more difficult.
  • return a pointer to a buffer allocated inside the function - although technically possible, this is the worst option, since you effectively pass on the ownership of the buffer; in other words, the caller must remember to free the buffer returned. In a simple program like the one you showed above, this may not seem like a big issue, but in a big program, that buffer may be passed around to far away places within the app, so there is a high risk that noone frees it in the end, thus leaking memory.
Péter Török
no, scanf works fine and i get the output if i print d inside raw_input, but in the main func. it not working :)
Rami Jarrar
It works find because your compiler happens to be very lenient and you are lucky. It is not guaranteed to work fine at all; you are overwriting random memory.
Max Shawabkeh
@Rami: Peter is definitely correct. What makes your program appear to work (actually, stumble around) is that you pass the address of d, which causes the input string from scanf() to overwrite the stack variables in function raw_input. Your function raw_input never returns.
Heath Hunnicutt
see my update :) for the func. call.
Rami Jarrar
I want to return the inputs, but no using for pointers to return it :)
Rami Jarrar
@Heath Hunnicutt Very good observation, I haven't even thought of that... however, to be precise, this happens only when the input from the console is longer than the size of the pointer (typically 4 bytes). I guess that @Rami so far only entered shorter inputs, that's why he hasn't observed the stack corruption yet.
Péter Török
@Rami see my update.
Péter Török
+2  A: 

The pointer d in the function is uninitialized. scanf would be filling up arbitrary memory. Instead, you need to pass a buffer (character array) for it to fill, and the buffer has to be defined in main, otherwise it'll be destroyed before you can return it (unless you do dynamic allocation, but that's another story).

Max Shawabkeh
You also want to take the time to ensure that the maximum number of characters read is less than will fit in the buffer.
Donal Fellows
A: 

You can not return a pointer of a variable that has been created inside the function. The variable d is not valid anymore in the main function.

try this: 1. create the variable d in the main function 2. and pass it to the raw_input function

void raw_input(char *msg, char *d)
markus
see my update :)
Rami Jarrar
+2  A: 
#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;
}

Try this, should work. The other answers pointed your errors out, as I can see... I was to slow ;)

EDIT: Ok, found an error... fixed it ;)

EDIT2: Max suggested a struct was possible, here is some code:

#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;
}
Juri Robl
Why the downvote? I'm new to this site, so at least tell me what I did wrong...Thank you.
Juri Robl
no, this will return the address of d not the content :)
Rami Jarrar
Wrong. `d` is on the stack inside `raw_input`. It is freed once `raw_input` returns, so the address returned points to freed memory, and behavior is undefined. You either need to `malloc` `d` or pass `d` into `raw_input` from `main`, as others have said.
Håvard S
Yes, I found this error the same time you commented.
Juri Robl
You can't return a string as value in C, you have to use pointers.
Juri Robl
@Genmutant: why not ?? why i cant return a string ??
Rami Jarrar
If you return a string, you have to return a pointer. A string is just an array of chars with a 0 at the end. And since you can't return an array as one value, you can't return a string as a value. In C you can only return *one* value, in this case you have to return a pointer to the first char of the string.
Juri Robl
Well, you can return a struct containing an array.
Max Shawabkeh
@Max: how to do this ??
Rami Jarrar
I added an example.
Juri Robl
@Genmutant: for Max Solution, its the same problem not working, now i'm hanging :D
Rami Jarrar
Where's the problem?
Juri Robl
its print the message and read the input but it doesn't print the Done,, then the problem in return and in input = raw_input("Message Here Is: ");
Rami Jarrar
Did you try my code above? Works for me...
Juri Robl
yea i'm talking about it, i'm using gcc on windows
Rami Jarrar
+1  A: 

Try this experiment:

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

Perform several experiements with input messages as long as: 3, 4, 5, 7, 8, 9, 11, 12, 13, etc. characters long. See what the result is for the integer variable value. You will see that due to your misuse of scanf() by passing the address of d, you are allowing scanf() to destroy local variables of your function, including the return address.

And that gets us back to the name of this web site.

Heath Hunnicutt
its not work like other codes, it just stop working when it about to print the output, i dont know whats the problem ??
Rami Jarrar
It's not supposed to work. It's supposed to show you that what you type in from the keyboard becomes part of the variable "value" somehow.
Heath Hunnicutt
its even dont print the value, it just take string from keyboard then stop working !!??
Rami Jarrar
+2  A: 

As mentioned, you aren't allocating memory for use with scanf. But never ever use scanf; it's hard to use correctly and to avoid buffer overflows. Use fgets.

From the comp.lang.c FAQ: Why does everyone say not to use scanf? What should I use instead?

Also, while unrelated to your problem, this bit of code is dangerous:

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

You are passing user-input directly to printf as a format strings, so this is susceptible to format string attacks if the printed string happens to include % characters. Better:

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

Also, you might want some newlines when you print. Also:

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

won't work because s doesn't point to anything, so you're dereferencing a garbage pointer. Assuming that you fix raw_input to return an allocated string, it should be:

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

Lastly (also unrelated to your problem):

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

You should call fflush(stdout) after printing the prompt. See My program's prompts and intermediate output don't always show up on the screen, especially when I pipe the output through another program.

jamesdlin
but how to return an allocated string,, this is exactly what i want ??
Rami Jarrar