Saving strings to structs using gets()? [duplicate] - c

This question already has answers here:
C: Multiple scanf's, when I enter in a value for one scanf it skips the second scanf [duplicate]
(7 answers)
Closed 6 years ago.
I'm running into some problems in saving a string - a name, for example - into a struct field. I've used gets() and fgets() both, but fgets() isn't working properly either.
I never get the chance to input the first employee name; it skips straight to the employee code and then skips the address too. For some reason, when inputting the second employee, I get to input both the name and code, and then it skips the address again.
Anyone know what I'm doing wrong?
#include <stdio.h>
typedef struct {
char name[150];
int code;
char add[300];
} tEmployee;
int main()
{
printf("How many employees would you like to register?\n");
int n;
scanf("%i", &n);
tEmployee employee[n];
for (int i = 0; i < n; i++)
{
printf("Name: ");
gets(employee[i].name);
printf("Code: ");
scanf("%i", &employee[i].code);
printf("Address: ");
gets(employee[i].add);
printf("%s\n", employee[i].name);
printf("%i\n", employee[i].code);
printf("%s\n", employee[i].add);
}
return 0;
}

The C library input routines aren't consistent about the way they handle newline (\n). Some read it as part of the input, some don't. Since scanf() gets what it needs before the newline, it has no reason to read it in so we have to so explicitly to clear it out of the buffer before our next input. There are different techniques but just calling getchar() works for this example.
Also, since gets() is considered unsafe, and leaves a newline dangling on the end of your input, I've added a custom my_gets() wrapper that fixes both issues:
#include <stdio.h>
#include <string.h>
typedef struct {
char name[150];
int code;
char add[300];
} tEmployee;
char *my_gets(char *str, int size)
{
char *pos;
char *result = fgets(str, size, stdin);
if (result != NULL && (pos = strchr(str, '\n')) != NULL)
*pos = '\0';
return result;
}
int main()
{
int n;
printf("How many employees would you like to register?\n");
scanf("%i", &n);
getchar(); // eat newline \n
tEmployee employee[n];
for (int i = 0; i < n; i++)
{
printf("Name: ");
my_gets(employee[i].name, 150);
printf("Code: ");
scanf("%i", &employee[i].code);
getchar(); // eat newline \n
printf("Address: ");
my_gets(employee[i].add, 300);
printf("%s\n", employee[i].name);
printf("%i\n", employee[i].code);
printf("%s\n", employee[i].add);
}
return 0;
}
You could make a similar wrapper function for your specific use of scanf() that eats the extra newline for you so you don't have to worry about it everytime you call that function for input.

It's your mixed use of gets and scanf. I've faced similar problem in C++, when I mixed the use of std::cin and >> operator and std::getline function.
Also, gets is deprecated, don't use it...
Anyway, if you really want to use the both, then you should "flush" stdin each time you use scanf, or the next time you read stdin you will read the rest of it till the end of line (the \n).
One way to do it, is to read till the end of line after each scanf:
/* define the function */
void flush()
{
while (getchar() != '\n');
}
Then use it in your code as follow:
printf("How many employees would you like to register?\n");
int n;
scanf("%i", &n);
flush();
tEmployee employee[n];
for (int i = 0; i < n; i++)
{
printf("Name: ");
gets(employee[i].name);
printf("Code: ");
scanf("%i", &employee[i].code);
flush();
printf("Address: ");
gets(employee[i].add);
printf("%s\n", employee[i].name);
printf("%i\n", employee[i].code);
printf("%s\n", employee[i].add);
}
return 0;

Try this:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[150];
int32_t code;
char add[300];
} tEmployee;
typedef uint_fast8_t bool_t;
/*****************************************************************************
* flush stdin... this should be standard but somewhy you need to reinvent
* it all the time...
*****************************************************************************/
static inline void flush_stdin()
{
char ch;
do {
ch = getchar();
} while ((ch != '\n') && (ch != EOF));
}
/*****************************************************************************
* reads a line of text from a stream.
*****************************************************************************/
static inline bool_t xio_fgetline(FILE *stream, char *linebuf, size_t szline)
{
fgets(linebuf, szline, stream);
// find last character.
char *lc = linebuf + strlen(linebuf) - 1;
// the only case when lc is a null is if the program memory
// has been altered. In this case, it should crash anyway.
// therefore I skip a nullcheck before chomping.
// chomp linebuf.
if (*lc == '\n') {
*lc = 0;
}
// string is {0} after chomping.
if (strlen(linebuf) == 0) {
return 0;
}
return 1;
}
/*****************************************************************************
* reads a line of text from stdin.
*****************************************************************************/
static inline bool_t xio_getline(char *linebuf, size_t szline)
{
return (xio_fgetline(stdin, linebuf, szline));
}
int main(int argc, char **argv)
{
int32_t n;
tEmployee *employee = (tEmployee *)0;
printf("How many employees would you like to register?\n");
scanf("%i", &n);
flush_stdin();
employee = (tEmployee *)malloc(n * sizeof(tEmployee));
for (int32_t i = 0; i < n; ++i) {
printf("Name: ");
xio_getline(employee[i].name, sizeof(employee[i].name));
printf("Code: ");
scanf("%i", &employee[i].code);
flush_stdin();
printf("Address: ");
xio_getline(employee[i].add, sizeof(employee[i].add));
printf("%s\n", employee[i].name);
printf("%i\n", employee[i].code);
printf("%s\n", employee[i].add);
}
free(employee);
return 0;
}

Related

For loop doesn`t work when add [^\n] to a scanf_s

This program should ask you to add member (people) to a struct and print them on a file but after the first for loop just stop working and jump over the name part. I just found that thing that allow you to add space to a string, tried it but no success...
I tried to remove it and it work without any problem so the [^\n] make something go wrong.
What is wrong ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Staff {
char Surname[100];
char Name[100];
int age;
char spec[100];
int id;
} person;
void write();
void leggi();
void trova();
int main() {
write();
}
void write() {
int i = 0;
int n = 1;
int r;
FILE *fp;
fopen_s(&fp, "index.txt", "w+");
if (fp == NULL) {
printf("Failed to open file\n");
exit(1);
}
fprintf(fp, "%d\n", i);
for (i = 0; i < n; i++) {
printf("Surame:\n");
scanf_s("%[^\n]s", person.Surname, 100);
fprintf(fp, "%s\t\t", person.Surname);
//loop just get over the name part
printf("Name:\n"); //after the first loop
scanf_s("%s", person.Name, 100);
fprintf(fp, "%s\t", person.Name);
printf("Age:\n");
scanf_s("%d", &person.age);
fprintf(fp, "%d\t", person.age);
printf("Specialization\n");
scanf_s("%s", person.spec, 100);
fprintf(fp, "%s\n", person.spec);
printf("Want to enter another? 1=yes 0=no...\n");
scanf_s("%d", &r);
if (r == 1)
n = n + 1;
}
rewind(fp);
fprintf(fp, "%d\n", i);
fclose(fp);
}
There are multiple problems in your code:
you use the so called secure functions fopen_s, scanf_s etc, but you do not check the return values to detect invalid input. You should instead use standard functions, pass the appropriate arguments and check the return values.
using scanf_s is actually non portable: the scanf_s function defined in Annex K of the C Standard requires the length argument after the pointer to have size_t type, whereas the function with the same name in the Microsoft library uses type UINT, which has a different representation on 64-bit versions of their Windows OS. A classical case of the Embrace, enhance and extinguish strategy. In Standard C, one should write: scanf_s("%s", person.Name, (size_t)100) or better:
scanf_s("%s", person.Name, sizeof person.Name)
there is no need to open the output file for update with "w+", just use "w".
you rewind the stream pointer back to the beginning of file and overwrite the number of entries at the start of the file. This works as long as you have less than 10 entries, but beyond that, the number has more digits so some characters in the file will be corrupted. You could use a format with padding such as "%6d\n" which would allow for up to 1 million records without risks.
"%[^\n]s" is not a correct scanf format: you should just write "%[^\n]" or better " %99[^\n]" to skip initial white space and limit the input to 99 characters.
Here is a modified version:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Staff {
char Surname[100];
char Name[100];
int age;
char spec[100];
int id;
};
void write(void);
void leggi(void);
void trova(void);
int main() {
write();
}
int flush_input(void) {
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
return c;
}
void write(void) {
int n = 0;
int r;
FILE *fp = fopen("index.txt", "w");
if (fp == NULL) {
fprintf("Failed to open file index.txt: %s\n",
strerror(errno));
exit(1);
}
fprintf(fp, "%6d\n", n);
for (;;) {
struct Staff person = { 0 };
printf("Surname:\n");
if (scanf(" %99[^\n]", person.Surname) != 1)
break;
flush_input();
fprintf(fp, "%s\t\t", person.Surname);
//loop just get over the name part
printf("Name:\n"); //after the first loop
scanf(" %99[^\n]", person.Name);
flush_input();
fprintf(fp, "%s\t", person.Name);
printf("Age:\n");
scanf("%d", &person.age);
flush_input();
fprintf(fp, "%d\t", person.age);
printf("Specialization\n");
scanf(" %99[^\n]", person.spec, 100);
flush_input();
fprintf(fp, "%s\n", person.spec);
n++;
printf("Want to enter another? 1=yes 0=no...\n");
if (scanf("%d", &r) != 1 || r != 1) {
flush_input();
break;
}
flush_input();
}
rewind(fp);
// update the entry count on 6 characters
fprintf(fp, "%6d\n", n);
fclose(fp);
}
Change the call of scanf below for entering strings by inserting a space in the beginning of the format string. For example instead of this call
scanf_s("%[^\n]s", person.Surname, 100);
(where the letter s must be removed from the format string) write
scanf_s(" %[^\n]", person.Surname, ( rsize_t )100);
^^^^^^^^
This allows to skip leading white space characters in the input buffer.
Pay attention to that changing the condition or the for loop the was as you are doing
for (i = 0; i < n; i++) {
//...
if (r == 1)
n = n + 1;
}
makes the code unclear. Instead of the for loop you could use do-while loop.

C: Program skips next input

My program skips the next input after 1 pass through it. I have read the threads on removing the newline character that fgets has, but nothing that was suggested worked. Is there anything that would work with microsoft visual studio? The best suggestion was "words[strcspn(words, "\r\n")] = 0;" and this did not remove the new line, unless I am formatting it incorrectly. I am not allowed to use the strtok function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 50
#define STOP "quit\n"
char *copywords(char *dest, const char *source, size_t n);
int main(void)
{
char words[50];
char newwords[50];
size_t num;
for (;;) {
printf("\nType a word, or type 'quit' to quit: ");
(fgets(words, SIZE, stdin));
if (strcmp(words, STOP) == 0) {
printf("Good bye!\n");
return 0;
}
printf("Type the # of chars to copy: ");
scanf_s("%d", &num);
copywords(newwords, words, num);
printf("The word was %s\n", words);
printf("and the copied word is %s", newwords);
}
}
char *copywords(char *dest, const char *source, size_t n) {
size_t i;
for (i = 0; i < n && source[i] != '\0'; i++) {
dest[i] = source[i];
}
dest[i] = '\0';
return dest;
}
The problem is that you leave the \n on the input when you call scanf. i.e. the user types number[return]. You read the number. When you loop around and call fgets agains the return is still waiting to be read so thats what fgets gets and it returns immediately.
I would probably just call fgets the second time you want to read input as well and then use sscanf to read from the string. i.e.
printf("Type the # of chars to copy: ");
fgets(buffer, ...)
sscanf(buffer, "%d", ...)
As an aside I would also say to check return values as it is easy for fgets or *scanf to fail.
My program skips the next input after 1 pass through it.
If I understand you correctly, the problem is that scanf_s (which I assume is like the C standard's scanf) will read the digits into num, but scanf won't remove the following newline from stdin, and so in the next iteration of the loop fgets will see that newline and behave as if it had seen a blank line.
I have usually avoided scanf for this reason and instead read a line into a buffer and then parse it. For example:
char buf[50];
...
fgets(buf,sizeof(buf),stdin);
sscanf(buf,"%d",&num);
(I'd also recommend adding a whole lot more error checking throughout.)
Here's a straightforward solution.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 50
#define STOP "quit\n"
char *copywords(char *dest, const char *source, size_t n);
int main(void)
{
char words[50];
char newwords[50];
size_t num, run = 0;
for (;;) {
printf("\nType a word, or type 'quit' to quit: ");
if(run)
getchar();
(fgets(words, SIZE, stdin));
if (strcmp(words, STOP) == 0) {
printf("Good bye!\n");
return 0;
}
printf("Type the # of chars to copy: ");
scanf("%d", &num);
copywords(newwords, words, num);
printf("The word was %s\n", words);
printf("and the copied word is %s", newwords);
run = 1;
}
}
char *copywords(char *dest, const char *source, size_t n) {
size_t i;
for (i = 0; i < n && source[i] != '\0'; i++) {
dest[i] = source[i];
}
dest[i] = '\0';
return dest;
}
Since we know there will be an extra '\n' character left in the stream due to the scanf, just take it out.

Input string with getchar

I am trying to read a string into a char array with a length chosen by the user. The problem is that getchar() doesn't stop reading until the user manually enters a newline by pressing enter, based on my code. I have read through other's threads, and I understand why I'm not able to do it this way, it's just completely contradictory to my assignment handout.
int chPrompt(int nchars);
void strInput(char str[], int nchars);
int main(void) {
int nchars = chPrompt(nchars);
char str[nchars];
strInput(str, nchars);
return 0;
}
int chPrompt(int nchars) {
printf("How many chars do you need to input? >");
return scanf("%i", &nchars);
}
void strInput(char str[], int nchars) {
int i = 0;
while((str[i] = getchar()) != '\n') {
if(i > nchars-1)
break;
i++;
}
str[i] = '\0';
//Troubleshooting
printf("%s %d", str, strlen(str));
}
This is what the handout says:
Input a string from the keyboard (spaces included) using the technique we talked
about (while with getchar(), not gets() , fgets()or scanf() ),
augmented so that it will input any amount up to, but no more than, 80
characters. Be sure that there’s a null in the proper location after the input.
The technique we talked about in class was the while loop with getchar assignment to char array.
My question:
My professor is very adamant about his instructions. In this handout, he is specifically telling me to input any amount up to, but no more than, 80. This is contradicting the functionality of getchar, correct? Is there any way to limit the length of a string, using this 'technique'?
On some of the threads I found, people mentioned it might be OS dependent. So, if that matters, I am on Windows 8.1.
Op's code is close.
"getchar() doesn't stop reading until the user manually enters a newline by pressing enter" is incorrect.
Typical user input is line buffered. Nothing is given to the program until Enter occurs. At that time the entire line is given to the program. getchar() consumes 1 char at a time from stdin.
1) Need to allocate sufficient buffer memory #Grzegorz Szpetkowski
2) Read input as an int and read extra as needed.
3) Do not return the value from scanf() as the number of to read.
4) Read remaining line after reading the number of char to be read. #Grzegorz Szpetkowski
getchar() returns an unsigned char or EOF. That is typically 257 different results. Reading getchar() into a char loses that distinction.
void strInput(char str[], int nchars) {
int i = 0;
int ch;
while((ch = getchar()) != '\n' && ch != EOF ) {
if (i < nchars) {
str[i++] = ch;
}
}
str[i] = '\0';
}
int main(void) {
int nchars = chPrompt(nchars);
char str[nchars + 1]; // + 1
strInput(str, nchars);
//Troubleshooting
printf("'%s' %zu", str, strlen(str));
return 0;
}
int chPrompt(int nchars) {
printf("How many chars do you need to input? >");
if (scanf("%i", &nchars) != 1) {
printf("Unable to read #\n");
exit(-1);
}
// Consume remaining text in the line
int ch;
while((ch = getchar()) != '\n' && ch != EOF );
return nchars;
}
Note: strlen() returns type size_t, not int, this may/may not be the same on your platform, best to use the right format specifier "%zu" with strlen(). Alternatively use:
printf("'%s' %d", str, (int) strlen(str));
This code could be corrected in few more places (e.g. counting the characters inputted so that you allow the user to input no more than 80 characters, etc.) but this will point you in the right direction:
#include <stdio.h>
#include <string.h>
void strInput(char str[], int nchars);
int main(void) {
int nchars = 0;
printf("How many chars do you need to input?\n");
scanf("%d\n", &nchars);
char str[nchars+1];
strInput(str, nchars);
return 0;
}
void chPrompt(int nchars) {
}
void strInput(char str[], int nchars) {
int i = 0;
char c;
while((c = getchar()) != '\n' && i <= (nchars-1)) {
str[i] = c;
i++;
}
str[i] = '\0';
printf("%s %d\n", str, (int)strlen(str));
}
little change to above answers,Try this it is not giving any "buffer full error"
#include<stdio.h>
#include<string.h>
void getinput(char str1[],int s){
int i=0;
printf("inside fn\n");
char c;
while((c=getchar())!=EOF && i<=(s-1))
{ str1[i++]=c;
}
str1[i]='\0';}
void main()
{ int size;
printf("enter the no. of characters \n");
scanf("%d", &size);
char str1[size+1];
getinput(str1,size);
printf("%s \n",str1);
}

scanf " %c" does not read whitespace in C

I need to read user input characters including whitespace and store them in linked list. If i use scanf("%c", &charas) it runs loop 2 times and allows to input only 1 time. If i use scanf(" %c", &charas) it does not read whitespace.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct sarasas {
char zenklas;
struct sarasas *kitas;
};
typedef struct sarasas Sarasas;
typedef Sarasas *SarasasPtr;
int tarpas(struct sarasas* sar, int index)
{
struct sarasas* dabartinis = sar;
int i;
for (i=1; i<=index; i++)
{
if (dabartinis->zenklas == 32)
return(i);
dabartinis=dabartinis->kitas;
}
}
int main()
{
int i, n, tarpo_vieta;
char charas;
SarasasPtr sar;
sar=(SarasasPtr) malloc(sizeof(Sarasas));
SarasasPtr pradzia=sar;
printf("Iveskite skaiciu n\n");
scanf("%d", &n);
printf("Veskite elementus: \n");
for(i=1;i<=n;i++)
{
printf("%d\n", i);
scanf("%c\n", &charas);
sar->zenklas=charas;
sar->kitas=(SarasasPtr) malloc(sizeof(Sarasas));
sar=sar->kitas;
}
sar->kitas=NULL;
//tarpo_vieta=tarpas(pradzia, n);
printf("%d\n", tarpo_vieta);
for (i=1;i<=n;i++)
{
printf("%c\n", pradzia->zenklas);
pradzia=pradzia->kitas;
}
}
Also i cannot use arrays.
use fgets
fgets(comment, sizeof comment, stdin);
Or
use
scanf("%[^\n]",word);
Use this one, some time our scanf and and also gets will not work properly, these happen so to read the value using different read function,
scanf("%[^\n]s",word);
this scanf will read your value upto new line means till you will not key enter this will read your input(size of string is a limit).
scanf("%[^*]",word);
this will read up to your '*' char if you pressed.
Try using getchar() to read one character instead of scanf():
charas = getchar();
First try running this:
char c;
do {
c = getchar();
putchar(c);
} while (c != '.');
While the code apparently deals with a single character per loop, what the program actually does it it takes input of any length from the user and then prints it character by character until it encounters a period.
You can use a similar loop, just instead of putchar in my code, write the code to add c to the linked list.
The problem lies with scanf("%d", &n); as although is does read in int n, it leaves the '\n' or Enter in stdin. This is scanned in with the next scanf("%c\n", &charas);.
Also a problem: scanf("%c\n", &charas); which does not return until a char, optional white-space (like \n, all which is consumed) and a non-white-space is entered. (That non-white-space is returned to stdin though)
As #miushock says, check scanf() family results.
Rather than:
scanf("%d", &n);
for(i=1;i<=n;i++) {
scanf("%c\n", &charas);
sar->zenklas=charas;
}
Do
char buf[40];
if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EOForIOError();
if (sscanf(buf, "%d", &n) != 1) Handle_InputError();
for (i=1; i<=n; i++) {
if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EOForIOError();
if (strlen(buf) != 2) Handle_InputError();
sar->zenklas = buf[0];
}

Suggest an alternative for gets() function, using gcc compiler

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"
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.
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.
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.
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);
Why use fgets?
Because it is more secure than gets.
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.
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.
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.
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.....

Resources