3

Trying to input more than a single string in my program's strings array, for that used :

scanf("%80[^\r\n]", strings[i]);

fgets(string[i], MAXLEN, stdin);

a custom made function was also used:

int getString(char s[]) {

    char ch;
    int i=0;

    while( (ch = getchar()) != '\n'   &&   ch != EOF ) {
        s[i] = ch;
        ++i;
    }

    s[i] = '\0';

    fflush(stdin);

    return i;
}

but unable to get input with more than one string each including white spaces

function gets() used to work earlier for me but since it is deprecated no alternative can be found

This is where it was used :

int getString(char s[]) {

char ch;
int i=0;

while( (ch = getchar()) != '\n'   &&   ch != EOF ) {
    s[i] = ch;
    ++i;
}

s[i] = '\0';

fflush(stdin);

return i;
}


struct vechileData
{
char vechileType[MAXLEN];
int begin_month;
int end_month;
    double price;
} data[5];


int main(int argc, char const *argv[])
{
printf("Input Vechile data: \n");

int i=0;
while(i < 5) {
    printf("Input vechile Type : \n");
    fgets(data[i].vechileType, MAXLEN, stdin);

    printf("Input begin month : \n");
    scanf("%d", &data[i].begin_month);

    printf("Input end monhth : \n");
    scanf("%d", &data[i].end_month);

    printf("Input price : \n");
    scanf("%lf", &data[i].price);

    ++i;
}

printf("Input Vechile Type to display information about the vechile : \n");
char vech[MAXLEN];
fgets(vech, MAXLEN, stdin);

i=0;
while(i < 5) {
    if (strcmp(vech,data[i].vechileType) == 0)
    {
        printf("vechileType: %s\n", data[i].vechileType);
        printf("Begin month: %d\n", data[i].begin_month);
        printf("End month: %d\n", data[i].end_month);
        printf("Price : %lf\n", data[i].price);
    }
    ++i;        
}

return 0;
}

It skips the next input to string statement during run time, "seems to"

amarVashishth
  • 847
  • 3
  • 12
  • 26

5 Answers5

7

Your problem is really not a gets() issue.

None of the scanf("%d", ...) and scanf("%lf", ...) consume the '\n' after the number and thus contribute to your issue. It is the next read of stdin to take in the '\n'. So when the next car type is read, it gets the lingering '\n'. Your 2nd car type ends up being "\n".

Use of fgets(data[i].vechileType, MAXLEN, stdin); puts a '\n' in data[i].vechileType. You likely do not want this. Your former use of gets() consumed, but did not put the '\n' in its return.

I long ago gave up doing user input with scanf() due to these subtle issues. Recommend to separate input from parsing, use fgets() and then sscanf(). Example:

char number[80];
if (fgets(number, sizeof(number), stdin)) {
  sscanf(number, "%d", &x)

Your implementation of a gets() replacement differs as follows

1) It does not return s (or NULL or error/eof).
2) It does not set eof indicator on eof. 3) Should getchar() return a '\0', your while loop errantly continues.


Recommend that if you must replace gets(), do so via fgets().

#define My_gets_N (1024 /* Some BA number */)

char *My_gets(char * str) {
  char buffer[My_gets_N];
  char *retval = fgets(buffer, sizeof(My_gets_N), stdin);
  if (retval) {
    int l = strlen(buffer);
    /* fgets() saves '\n', but gets() does not */
    if ((l > 0) && (buffer[l-1] == '\n')) {
      l--;
    }
    memcpy(str, buffer, l);
    str[l] = '\0';
    return str;
  }
  else {
    return 0;
  }
}

If you replacement solution needs to deal with string length > the fixed My_gets_N, other coding is needed.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
2

You must be more specific about what went wrong with the fgets() approach, that's the one I would recommend and it does work.

Note that fgets() will input the entire line, including linefeed/carriage returns at the end, so you might need to clean those off if they're undesirable to keep.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • exactly, this is the problem, i have to search the entire string for the '\n' character then replace it by '\0'. Do u have an alternative for this, i mean replacing nexline by null – amarVashishth Jun 05 '13 at 14:32
1

I don't understand how gets() worked for you, despite the warning that practically every C book post K&R gives, as it's not only deprecated, but extremely dangerous to use. Like the others have said, fgets() would definitely work if you used it correctly.

  • Yes, extremely dangerous. The `gets()` function is defined to read input into a buffer provided by the caller, up to and including the first newline (or EOF). It does not provide any mechanism for limiting input to the size of the buffer, the _only_ limit to how much `gets()` will read is "newline, or EOF". The `fgets()` function, at least, allows you to specify the size of the buffer you're using. – This isn't my real name Jun 05 '13 at 23:47
0

Instead of replacing all the instances of uses of gets with fgets. Use following Macros:

#define TRUNCATE_NULL(strText) \
 { \
   int _strlen = strlen(strText); \
   if (_strlen > 0 && strText[_strlen - 1] == '\n') strText[_strlen - 1] = '\0'; \
   else while(fgetc(stdin)!='\n'); \
 }
#define gets(strText) fgets(strText, sizeof(strText), stdin); TRUNCATE_NULL(strText);
  1. Why use fgets?

    Because it is more secure than gets.

  2. Is gets really insecure?

    Yes. It is greedy indeed, it will accept as much food as you give, even if it can not eat.
    So technically, as @halfer rightly commented below,
    with the use of gets, program is prone to buffer overflow.

  3. How ?

    char name[5];
    gets(name);
    

    Now provide input of more than 5 characters, it will accept it.
    This would overwrite data from memory, which should not be overwritten this way.

  4. Ok with fgets, but why use TRUNCATE_NULL macro ?

    fgets is not perfect either. it will accept \n (Enter) as character to be placed in input name.
    So to remove unnecessary \n, and to make sure expected functionality of gets is achieved we can use it.

prashant
  • 1,144
  • 9
  • 15
  • 1
    I have adjusted the grammar here, and removed some coarse language that was unnecessary. It was rather confusing, what do you mean about "accepting as much food as you can give"? If this is a reference to buffer overflow, there is probably a better way to word this! – halfer Dec 18 '16 at 00:43
  • Thanks @halfer, It might be possibility that I was hungry while answering here. – prashant Dec 21 '16 at 14:27
  • OK, feel free to reword if you can! – halfer Dec 21 '16 at 14:28
0

Actually, there you can use while((getchar())!='\n'); to avoid such type of problem and one thing there is no need to use of fflush(stdin) function. Here's code you can use

#include<stdio.h>
#include<string.h>
#define MAXLEN 50
int getString(char s[]) 
{
    char ch;
    int i=0;
    while( (ch = getchar()) != '\n'   &&   ch != EOF )
    {
        s[i] = ch;
        ++i;
    }
    s[i] = '\0';
    return i;
}
struct vechileData
{
    char vechileType[MAXLEN];
    int begin_month;
    int end_month;
    double price;
}data[5];
int main(int argc, char const *argv[])
{
    printf("Input Vechile data: \n");
    int i=0;
    while(i < 2)
    {
        printf("Input vechile Type : \n");
        fgets(data[i].vechileType, MAXLEN, stdin);

        printf("Input begin month : \n");
        scanf("%d", &data[i].begin_month);

        printf("Input end monhth : \n");
        scanf("%d", &data[i].end_month);

        printf("Input price : \n");
        scanf("%lf", &data[i].price);
        while((getchar())!='\n');
        ++i;
    }    
    printf("Input Vechile Type to display information about the vechile : \n");
    char vech[MAXLEN];
    fgets(vech, MAXLEN, stdin);
    i=0;
    while(i < 2)
    {
        if (strcmp(vech,data[i].vechileType) == 0)
        {
            printf("vechileType: %s\n", data[i].vechileType);
            printf("Begin month: %d\n", data[i].begin_month);
            printf("End month: %d\n", data[i].end_month);
            printf("Price : %lf\n", data[i].price);
        }
        ++i;
    }
    return 0;
}

I hope this will help you.....