views:

155

answers:

6
int main(void) {
    char *input;
    printf("prompt>");
    scanf("%s", input);
    printf("%s", input);
    return 0;
}

prompt>input

RUN FAILED (exit value 138, total time: 3s)

What's wrong with the code? Has to be either the scanf() or the second printf(). The input is of unknown length. A lot people have said to simply create a char array of length 'X' to hold the input. Just wanted to know then why this code works.

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

int main(void) {
    /* prompt */
    char input;
    printf("prompt>");
    scanf("%s", &input);
    printf("%s", &input);
    return 0;
}
+3  A: 

char *input;

Is only a pointer - there is no data space allocated store the data that scanf collects.

try this instead

char input[100];
Preet Sangha
what if the length of the input is unknown or greater than 99 characters?
Spencer
This is separate question and you should either update your original question or make a new one.
Mahmoud Abdelkader
+1  A: 

You may want to try scanf("%c", input) inside of a while loop that has your delimiting character. You should also make input an array char input[X] where X is a number of sufficient value to hold the most likely values for your input. I would try making input an array first though.

bluevial
what if the length of the input is unknown?
Spencer
Attempt to make the input buffer large enough to hold it's most likely values, if you really think that you need a resizable buffer then that is another question. Edited to show.
bluevial
A: 

What compiler do you use? In Turbo C 3.0 it works. Try this variant:

#include <stdio.h>
#include <alloc.h>
int main(void) 
{
    char *input = (char*)calloc(100, sizeof(char));
    printf("prompt>");
    scanf("%s", input);
    printf("%s", input);
    free(input);
    return 0;
}
yozhik
Turbo C 3.0????
James McNellis
Turbo C is a free C++ compiler from Borland. It comes with an IDE and debugger. It was first introduced in 1987 and was Famous for its integrated development environment, small size, very fast compile speed, comprehensive manuals and low price. http://www.brothersoft.com/turbo-c-182798.html
Spencer
It's also totally unnecessary (and not overly modern-standards-compliant) nowadays with the likes of Code::Blocks and the Visual Express editions from MS :-)
paxdiablo
Why are you using a Cold War era compiler?
caf
I'm studying and in our university we have very-very-very old computers from the Cold War)) thats why I am using it for pure C related tasks. For my own purpose I am using VS 6.0, 2008.
yozhik
turbo c improve one's endurance)) really
yozhik
+1  A: 

You forgot to allocate the memory before using your pointer.

Try it:

int main(void) {
    char input[256];
    printf("prompt>");
    scanf("%s", input);
    printf("%s", input);
    return 0;
}

or even:

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

int main(void) {
    char *input = (char *) malloc(sizeof(char) * 256));
    printf("prompt>");
    scanf("%s", input);
    printf("%s", input);
    return 0;
}
SpamKids
+6  A: 

Your specific problem is that you have no storage behind input. It's an uninitialised pointer, pointing to a random spot in memory, which is unlikely to be anywhere useful.

You can use something like:

char *input = malloc (100);
// check that input != NULL
// use it
free (input);

or:

char input[100];

but you have a serious problem with your use of scanf (see below).


You should never use an unbounded %s in scanf (or any of its variants unless you totally control the input). It's a dangerous practice prone to buffer overflows and the sooner you get out of the habit, the better. It's akin to gets() in that way.

From an earlier answer of mine, this piece of code below (along with your main code incorporated into it) provides a safe way of getting user input. You pass in an optional prompt, the buffer to load the input into, and the size of the buffer.

It will return the input up to the size of the buffer (stripped of the newline if there) then clear out the rest of the line if necessary so that it doesn't affect the next input operation. It will return either OK or an error indication on end-of-file or if the input was too long (you still get the first part of the input in case you want to do something with it).

Once you have the line, you can sscanf it, safely, to your heart's content. However, that's not required in your case since you're only trying to get a string. Just use the buffer that's returned directly.

#include <stdio.h>
#include <string.h>

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

 

int main(void) {
    char input[10];
    int rc = getLine ("prompt> ", input, sizeof (input));
    switch (rc) {
        case NO_INPUT: printf ("\nNo input recieved\n"); break;
        case TOO_LONG: printf ("Too long, truncated input below:\n");
        default: printf("Your input was [%s]\n", input);
    }
    return 0;
}

Give that a shot, it's far more robust than using scanf("%s") on its own.


As for your update asking why this works:

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

int main(void) {
    /* prompt */
    char input;
    printf("prompt>");
    scanf("%s", &input);
    printf("%s", &input);
    return 0;
}

It's undefined code. Period. You only allocate space for a character but you scan in a string. Since a string is a character array of all the characters followed by a zero character, the only string you could input safely there would be an empty one.

Anything else will write to both the character and whatever happens to be adjacent to the character on the stack.

This is no different to allocating char input[100] then entering 200 characters, it's still buffer overflow and should be avoided.

Discussion below is based on a particular implementation of C, not necessarily all implementations.

Chances are, you got lucky here. Compilers may generate code that keeps the stack pointer aligned so that, even though you asked for one byte, you may get space allocated for four (or even more, depending on the architecture - I'll assume most types are four bytes here for simplicity).

In addition, you may find that you can also safely overwrite the eight bytes of argc integer and argv pointer (they're probably still there even though you don't use them, no point having two different sets of start-up code just to save a few bytes on the stack).

If you write further than that, you'll eventually overwrite the return address from main to your start-up code. Then you'll know about it since your code will go off into la-la land when main exits.

With undefined behaviour, anything can happen. Sometimes that anything includes the possibility that it will work perfectly (similar to "throw a deck of cards in the air often enough and they'll eventually fall in a nice neat sorted heap" but a little less random).

That does not make undefined behaviour any less of a bad thing.

paxdiablo
A: 

Try:-

int main(void) { 
char input[100]; 
printf("prompt>"); 
scanf("%99s", input); 
printf("%s", input); 
return 0; 

}

This will limit the string to 99 bytes. Note "%s" == string of characters delimited by white space or newline ie. you only get the first word!

I think what you really want is:

#include <stdio.h>
int main(void) { 
    char input[99]; 
    printf("prompt>"); 
    fgets(input,99,stdin);
    printf("->%s<-", input); 
    return 0; 
} 

You probably need to add some code to get rid of unwanted new line characters!

James Anderson