70

I want to read a string entered by the user. I don't know the length of the string. As there are no strings in C I declared a pointer:

char * word;

and used scanf to read input from the keyboard:

scanf("%s" , word) ;

but I got a segmentation fault.

How can I read input from the keyboard in C when the length is unknown ?

jww
  • 97,681
  • 90
  • 411
  • 885
mainajaved
  • 7,905
  • 10
  • 36
  • 44

6 Answers6

76

You have no storage allocated for word - it's just a dangling pointer.

Change:

char * word;

to:

char word[256];

Note that 256 is an arbitrary choice here - the size of this buffer needs to be greater than the largest possible string that you might encounter.

Note also that fgets is a better (safer) option then scanf for reading arbitrary length strings, in that it takes a size argument, which in turn helps to prevent buffer overflows:

 fgets(word, sizeof(word), stdin);
Paul R
  • 208,748
  • 37
  • 389
  • 560
  • 35
    -1: He said the length is unknown and your choice of `256` is entirely arbitrary, so you just (well, 2½ years ago) taught him how to write buffer overruns and huge security flaws. Congratulations. – Lightness Races in Orbit Jun 11 '14 at 17:19
  • 13
    Thank for you for the (somewhat belated) criticism - I've now updated the answer to cover not just the dangling pointer but also the recommendation to use `fgets` rather than `scanf` for arbitrary length string input. – Paul R Jun 12 '14 at 06:53
  • 8
    Ah, wonderful. :) +1. As for it being belated, to be fair, glglgl said it below, just thirty-four minutes after you posted the answer! ;) – Lightness Races in Orbit Jun 12 '14 at 09:12
27

I cannot see why there is a recommendation to use scanf() here. scanf() is safe only if you add restriction parameters to the format string - such as %64s or so.

A much better way is to use char * fgets ( char * str, int num, FILE * stream );.

int main()
{
    char data[64];
    if (fgets(data, sizeof data, stdin)) {
        // input has worked, do something with data
    }
}

(untested)

glglgl
  • 89,107
  • 13
  • 149
  • 217
25

When reading input from any file (stdin included) where you do not know the length, it is often better to use getline rather than scanf or fgets because getline will handle memory allocation for your string automatically so long as you provide a null pointer to receive the string entered. This example will illustrate:

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

int main (int argc, char *argv[]) {

    char *line = NULL;  /* forces getline to allocate with malloc */
    size_t len = 0;     /* ignored when line = NULL */
    ssize_t read;

    printf ("\nEnter string below [ctrl + d] to quit\n");

    while ((read = getline(&line, &len, stdin)) != -1) {

        if (read > 0)
            printf ("\n  read %zd chars from stdin, allocated %zd bytes for line : %s\n", read, len, line);

        printf ("Enter string below [ctrl + d] to quit\n");
    }

    free (line);  /* free memory allocated by getline */

    return 0;
}

The relevant parts being:

char *line = NULL;  /* forces getline to allocate with malloc */
size_t len = 0;     /* ignored when line = NULL */
/* snip */
read = getline (&line, &len, stdin);

Setting line to NULL causes getline to allocate memory automatically. Example output:

$ ./getline_example

Enter string below [ctrl + d] to quit
A short string to test getline!

  read 32 chars from stdin, allocated 120 bytes for line : A short string to test getline!

Enter string below [ctrl + d] to quit
A little bit longer string to show that getline will allocated again without resetting line = NULL

  read 99 chars from stdin, allocated 120 bytes for line : A little bit longer string to show that getline will allocated again without resetting line = NULL

Enter string below [ctrl + d] to quit

So with getline you do not need to guess how long your user's string will be.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Re `fgets()` v. `getline()`. The _limitless_ `getline()`, IMO is too near a hacker exploit as it allows externally supplied data to overwhelm a program. Yet a fixed buffer (`fgets()`) is too limiting. I've toyed with m'allocating a huge buffer for `fgets()` and relying on [*delayed allocation](http://stackoverflow.com/q/19991623/2410359) to control things. – chux - Reinstate Monica May 01 '15 at 18:35
  • Correct you are. As a lark, I used `getline` to buffer an `868789` character string -- no complaints. I'll dig into your delayed allocation link and see what pearls/perils are there. There is just no replacement for the flexibility `getline` offers. I've tinkered with writing replacements using `fgetc`, but you end rewriting `getline` more or less. The protection in `getline` is the fact it does continue to allocate, preventing an overrun, but it puts to onus on you to check the size of the result for reasonableness... – David C. Rankin May 01 '15 at 21:49
4
#include<stdio.h>

int main()
{
    char str[100];
    scanf("%[^\n]s",str);
    printf("%s",str);
    return 0;
}

input: read the string
ouput: print the string

This code prints the string with gaps as shown above.

Dalton Cézane
  • 3,672
  • 2
  • 35
  • 60
Ananth Reddy
  • 299
  • 1
  • 5
  • 16
3

You need to have the pointer to point somewhere to use it.

Try this code:

char word[64];
scanf("%s", word);

This creates a character array of lenth 64 and reads input to it. Note that if the input is longer than 64 bytes the word array overflows and your program becomes unreliable.

As Jens pointed out, it would be better to not use scanf for reading strings. This would be safe solution.

char word[64]
fgets(word, 63, stdin);
word[63] = 0;
Juho
  • 983
  • 5
  • 9
  • 2
    Which is why you should not use `scanf` in the first place to read a string; use `fgets` instead which takes a length argument. – Jens Oct 10 '11 at 07:10
  • @Jens: You are right and I should be ashamed for not providing better solution at first. I edited my answer in case someone comes to read it. – Juho Oct 10 '11 at 09:46
  • 1
    `fgets` already zero terminates the input string. Also, unlike `*scanf`, it accounts for that so using the full size of the array is idiomatic: `fgets(word, sizeof word, stdin)` – pmg Oct 10 '11 at 11:40
  • `fgets(word, 63, stdin); word[63] = 0;` --> `fgets(word, sizeof word, stdin);` – chux - Reinstate Monica May 01 '15 at 13:47
1

The following code can be used to read the input string from a user. But it's space is limited to 64.

char word[64] = { '\0' };  //initialize all elements with '\0'
int i = 0;
while ((word[i] != '\n')&& (i<64))
{
    scanf_s("%c", &word[i++], 1);
}
Blue Phoenix
  • 153
  • 11