0

I have written a small code to take multiple strings as input from user. Prior to that, I'm asking the user to input the number of strings to take as input. While taking strings as input, a new line character automatically occupies the the place of first string. I don't know what is happening :( Here is my code:

#include<stdio.h>
#include<string.h>
void main()
{
    char *arr[20],str[40];
    int n;
    printf("enter the number of strings\n");
    scanf("%d",&n);
    int i;
    printf("Enter the strings\n");[It isn't taking 3 strings as input,as a newline character is already occupying first place][1]
    for(i=0;i<n;i++)
    {
        gets(str);
        arr[i]=(char *)malloc(sizeof str);
        strcpy(arr[i],str);
    }
    printf("The Strings are:\n");
    for(i=0;i<n;i++)
    {
        printf(arr[i]);
        printf("\n");
    }
}
Joy
  • 63
  • 10
  • *Never, never* use `gets`. It has been removed from C11 due to it insecurity. Use `fgets` instead (e.g. `fgets (str, sizeof str, stdin)`). The answer to your question is `gets` and `fgets` (and `getline`) all read *up to and including* the `'\n'`. You will normally remove it before storing your string (e.g. `size_t len = strlen (str); if (str[len-1] == '\n') str[len-1] = 0;` so you don't have newlines dangling off some of your variables), but if you are just printing back to `stdout`, just don't add a `'\n'` in your `printf` statement. – David C. Rankin Nov 28 '16 at 04:39
  • Also, do *NOT* cast the return of `malloc`, it is unnecessary. See: [**Do I cast the result of malloc?**](http://stackoverflow.com/q/605845/995714) for thorough explanation. – David C. Rankin Nov 28 '16 at 04:44
  • yes, you are right, definitely fgets is more safe to use than gets as it alleviates the buffer overflow problem. Well is it the case that, the newline character is already waiting in the input buffer after I take number of strings as input? and while reading the first string, it sees a new line character already in the buffer and places it as the first string? – Joy Nov 28 '16 at 04:48
  • Since the contents of `arr[i]` are defined by the user, using `printf(arr[i]);` is appallingly unsafe. The user can type all sorts of things with `%` in it and break your program. `%245n` is pretty likely to cause a crash. Use `printf("[%s]\n", arr[i]);` or thereabouts, to give yourself a chance of seeing the data. The square brackets delimit the string to help you see leading and trailing blanks (and CR characters, etc). – Jonathan Leffler Nov 28 '16 at 05:06

3 Answers3

1

Following on from the comments, there are a number of issues you have in your code. First gets, don't use it, it is a 'hanging' offense -- enough said.

Next, validate all user input. For all you know, a cat could be stepping on the keyboard. Make sure you test what you receive as input, and that it matches what you expect.

Mixing scanf with line-oriented input (e.g. fgets or getline can cause problems for new users. Why? The scanf family of functions do not remove the '\n' and instead leaves it in the input buffer (e.g. stdin). When you then attempt to read with fgets the first character it sees in stdin is what? A '\n', which it reads and considers a whole line. If you are going to use scanf to read the number of strings, it is up to you to remove the '\n' that scanf left in stdin.

It's not hard, you can actually just use the assignment suppression operator provided by scanf in your format string. E.g.:

scanf ("%d%*c", &n);

The * is the assignment suppression operator, which when used with %*c simply tells scanf to read and discard the next character without adding to the match count (e.g. what scanf returns).

You will want to use a while loop instead of a for loop, (or use an independent index) when filling your array. Why? What if the users cancels input with a ctrl + d (or ctrl + z on windoze). If you are iterating up to n regardless of what the user does, you can easily attempt to index an array element that you haven't allocated, or allocate for a string that was not entered.

Putting it altogether, you can do something like:

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

enum { MAXA = 20, MAXS = 40 }; /* max ptrs and str */

int main (void) {

    char *arr[MAXA] = {NULL}, str[MAXS] = "";
    int i = 0, n = 0, ndx = 0;   /* initialize all variables */

    printf ("enter the number of strings: ");
    /* use assignment suppression %*c to discard the \n */
    if (scanf ("%d%*c", &n) != 1) { /* always validate input */
        fprintf (stderr, "error: invalid integer input.\n");
        return 1;
    }

    if (n > MAXA) { /* validate the value of n */
        fprintf (stderr, "warning: n > %d, using %d as limit.\n",
                MAXA, MAXA);
        n = MAXA;
    }

    printf("Enter the strings\n");
    while (ndx < n && fgets (str, sizeof str, stdin)) { /* validate input */
        size_t len = strlen (str); /* get the length */
        if (str[len - 1] == '\n')  /* check for '\n' */
            str[--len] = 0;        /* overwrite with nul-terminator */
        if (!(arr[ndx] = malloc (len + 1))) { /* validate allocation */
            fprintf (stderr, "error: virtual memory exhausted.\n");
            break;
        }
        strcpy (arr[ndx], str);   /* copy to array */
        ndx++;                    /* increment index */
    }

    printf("\nThe Strings are:\n");

    for (i = 0; i < ndx; i++) {  /* you have ndx strings not n */
        printf (" arr[%2d] : %s\n", i, arr[i]);
        free (arr[i]);  /* free memory when no longer needed */
    }

    return 0;
}

Example Use/Output

$ ./bin/nogets
enter the number of strings: 3
Enter the strings
My dog
has a lot
of fleas.

The Strings are:
 arr[ 0] : My dog
 arr[ 1] : has a lot
 arr[ 2] : of fleas.

Now try the same thing and press ctrl + d instead of entering "of fleas." (you are covered).

Lastly, in any code your write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. Get in the habit of tracking the memory you allocate, and free it rather than relying on it being done on exit. That will serve you well as your programs grow more complex.

Look over the code, and make sure you understand what is going on. Let me know if you have any questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Sir, I have learned a lot from your code and suggestions, I must admit ! I didn't have knowledge about lot of things before, but I have come to know about them from your answer. I've fairly understood your code and I'll try to follow this style from now on. – Joy Nov 28 '16 at 18:42
  • Glad I could help. A large part of programming is simply learning how break any given problem down into tasks that the language provides tools to solve. C is a particularly low-level language. Many times you are simply deciding how to handle bytes of memory. This question, reads bytes from `stdin` (the input buffer) and stores those bytes for later use. This includes integer input and character strings. There is a lot of learning wrapped up in this question. Take the time to understand the differences in how to handle integer, character, and floating point values. You will do fine. – David C. Rankin Nov 29 '16 at 05:29
0

When you read the number of digits using scanf, it only processed the digit typed in, not the enter you pressed after entering the digit.

Might be worth while to flush the rest of the for input such as How to clear input buffer in C?

Community
  • 1
  • 1
Bob Zhou
  • 1
  • 1
0

The gets() function shall read bytes from the standard input stream, stdin, into the array pointed to by s, until a <newline> is read or an end-of-file condition is encountered.

So whenever you enter after

enter the number of strings

5

So if you press enter then gets is getting called it's taking new line as a first input.

And if you didn't input enter and press like 5abc then enter then it's going to consider abc as a first string.

You need to clear buffer before gets.

Your correct program is

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void main()
{
        char *arr[20],str[40];
        int n;
        int ch;
        printf("enter the number of strings\n");
        scanf("%d",&n);
        int i;
        printf("Enter the strings\n");
        //flush the input stream
        while ((ch = getchar()) != '\n' && ch != EOF);
        for(i=0;i<n;i++)
        {
                gets(str);
                arr[i]=(char *)malloc(sizeof str);
                strcpy(arr[i],str);
        }
        printf("The Strings are:\n");
        for(i=0;i<n;i++)
        {
                printf("%s",arr[i]);
                printf("\n");
        }
}
Community
  • 1
  • 1
suren
  • 455
  • 3
  • 14