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.....
Related
I've made a user-defined function for reading input and replacing newline character '\n' with '\0' so when I use printf statement for printing the string it won't add newline at the end.
char xgets(char *line, int size, FILE *stdn)
{
//READS THE LINE
fgets(line, size, stdn);
//REMOVES NEWLINE CHARACTER '\n' AND ADDS '\0'
line[strcspn(line, "\n")] = '\0';
return line;
}
When I call xgets inside main() function it works properly, but when it is called in other user-defined function it does not wait for user-input.
I'm using Visual Studio 2015 for debugging my code.
Here's my code:
#include<stdio.h>
#include<stdlib.h>
#include<process.h>
//USER-DEFINED FUNCTION
char xgets(char *line, int size, FILE *stdn);
void sortm_hgrade();
void sortm_rcharge();
void header(void);
void header(void)
{
printf("*-*-*-*-*HOTEL_INFO*-*-*-*-*");
printf("\n\n");
}
char xgets(char *line, int size, FILE *stdn)
{
//READS THE LINE
fgets(line, size, stdn);
//REMOVES NEWLINE CHARACTER '\n' AND ADDS '\0' END LINE CHARACTER
line[strcspn(line, "\n")] = '\0';
return line;
}
#define MAX 1000
//PROGRAMS STARTS HERE
int main(void)
{
//VARIABLE-DECLARATION
int i = 0, j = 0, n = 0;
char line[MAX] = { 0 };
char o = { 0 };
char h[10] = { 0 };
//FUCNTION CALL-OUT
header();
printf("Type anything : ");
xgets(h, sizeof(h), stdin);
printf("Enter one option from the following : \n\n");
printf("(a) To Print out Hotels of a given Grade in order of charges. \n");
printf("(b) To Print out Hotels with Room Charges less than a given Value. \n");
printf("Please type a proper option. \n");
while (n == 0){
scanf_s(" %c", &o);
switch (o){
case 'a':
sortm_hgrade();
n = 1;
break;
case 'b':
sortm_rcharge();
n = 1;
break;
default:
printf("Option INVALID \n");
printf("Please type a proper option \n");
n = 0;
break;
}
}
//TERMINAL-PAUSE
system("pause");
}
void sortm_hgrade()
{
//FOR SORTING BY GRADE
char g[10] = { 0 };
printf("Enter the Grade : ");
xgets(g, sizeof(g), stdin);
printf("\n");
}
void sortm_rcharge()
{
printf("----");
}
You should change
scanf(" %c", &o);
to
scanf("%c ", &o);
This force scanf to consume trailing chars, like '\n'
In your code '\n' of user input for scanf %c is not consumed and it is consumed by fgets in your xgets function that exit immediately with an empty buffer.
BTW that solution can wok only if a single char is input by user.
Best code would be
char c;
while (n == 0)
{
o = getchar();
while ((c = getchar()) != EOF && c != '\n') ;
EDIT
With the second solution code is waiting, and discarding, chars until a '\n' is triggered or end of file. In your specific case (using stdin as console) EOF is not mandatory. It will be mandatory in case of input is being read from a "real file".
You need to skip the \n character after you take in a character. you can command scanf for that. fgets reads that newline character up first and then hence it terminates. use this
scanf(" %c *[^\n]", &o);
This should do the trick
I am new to C programming.
I was curious as to see how much I have learnt C.
Therefore I thought of creating a program in which I could simply create a file and write in it.
The name of the file, I thought, should be less that 100 chars. But it doesn't matter if it is a string or one word or a letter.
I couldn't complete because I was stuck on fact that how to input a string for a file name(eg, Project work, New Doc1, etc)
So I wrote this;
int main()
{
int a = 0;
while(a != 5)
{
puts("Put a number: ");
scanf("%i", &a);
if(a == 1)
{
char name[30];
printf("Put a name: ->>");
for(int i = 0;i < 31 && name[i] != '\n';i++)
{
name[i] = getchar();
}
char ex[50] = ".txt";
strcat(name,ex);
printf("%s",name);
}
}
return 0;
}
The problem is while inputting the name, it doesn't stop at the next (when I press enter) and some how it is not printing the right file name either.
There's a lot of problems with you approach.
It's not good to mix scanf with another input primitives, you must flush stdin from any remaining characters.
Any string must end in '\0' in order to mark that string as complete. So you must reserve space to this character.
When you concat you must obey the limit of the string.
If you use printf, the string will be only displayed after flushing the stdout (when you put '\n' in the end of the string, flush is done)
Try this:
#include <stdio.h>
#include <string.h>
int main()
{
int a = 0;
while(a != 5)
{
int ch;
puts("Put a number: ");
scanf("%d", &a);
/* flush any remaining characters */
while ((ch=getchar()) != EOF && ch != '\n'); /* issue 1 */
if(a == 1)
{
int i = 0;
char name[30];
printf("Put a name: ->>");
fflush(stdout); /* issue 4 */
while ((ch=getchar()) != EOF && ch != '\n' && i < 25) /* issue 3 */
name[i++] = ch;
name[i] = '\0'; /* issue 2 */
/* flush any remaining characters [if input > 25 chars] */
if (ch != EOF && ch != '\n') while ((ch=getchar()) != EOF && ch != '\n');
char ex[50] = ".txt";
strcat(name,ex); /* issue 3 */
printf("%s\n",name);
}
}
return 0;
}
Also, consider use getline and atoi instead of getchar and scanf
#include<stdio.h>
main()
{
static char stop_char='y';
char input=0;
do{
printf("please input a character\n");
scanf("\n%c",&input);
}while(input!=stop_char);
}
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);
}
basically in codeblocks for windows before each printf I have "fflush(stdin);" which works. When I copied my code to Linux, it doesn't work, nor does any of the alternatives for "fflush(stdin);" that I've found. No matter which way I seem to do it, the input doesn't seem to be clearing in the buffer or something in my code is incorrect.
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <ctype.h>
int main()
{
char pbuffer[10], qbuffer[10], kbuffer[10];
int p=0, q=0, k=0;
int r, i, Q, count, sum;
char a[3];
a[0]='y';
while(a[0]=='y' || a[0]=='Y')
{
printf("Enter a p value: \n");
fgets(pbuffer, sizeof(pbuffer), stdin);
p = strtol(pbuffer, (char **)NULL, 10);
printf("Enter a q value: \n");
fgets(qbuffer, sizeof(qbuffer), stdin);
q = strtol(qbuffer, (char **)NULL, 10);
printf("Enter a k value: \n");
fgets(kbuffer, sizeof(kbuffer), stdin);
k = strtol(kbuffer, (char **)NULL, 10);
while(p<q+1)
{
Q=p;
sum=0;
count=0;
while(Q>0)
{
count++;
r = Q%10;
sum = sum + pow(r,k);
Q = Q/10;
}
if ( p == sum && i>1 && count==k )
{
printf("%d\n",p);
}
p++;
a[0]='z';
}
while((a[0]!='y') && (a[0]='Y') && (a[0]!='n') && (a[0]!='N'))
{
printf("Would you like to run again? (y/n) ");
fgets(a, sizeof(a), stdin);
}
}
return 0;
}
Calling fflush(stdin) is not standard, so the behavior is undefined (see this answer for more information).
Rather than calling fflush on stdin, you could call scanf, passing a format string instructing the function to read everything up to and including the newline '\n' character, like this:
scanf("%*[^\n]%1*[\n]");
The asterisk tells scanf to ignore the result.
Another problem is calling scanf to read a character into variable a with the format specifier of " %s": when the user enters a non-empty string, null terminator creates buffer overrun, causing undefined behavior (char a is a buffer of one character; string "y" has two characters - {'y', '\0'}, with the second character written past the end of the buffer). You should change a to a buffer that has several characters, and pass that limit to scanf:
char a[2];
do {
printf("Would you like to run again? (y/n) \n")
scanf("%1s", a);
} while(a[0] !='y' && a[0] !='Y' && a[0]!='n' && a[0]!='N' );
}
I think what you are trying to do is more difficult than it seems.
My interpretation of what you are trying to do is disable type ahead so that if the user types some characters while your program is processing other stuff, they don't appear at the prompt. This is actually quite difficult to do because it is an OS level function.
You could do a non blocking read on the device before printing the prompt until you get EWOULDBLOCK in errno. Or the tcsetattr function family might help. It looks like there is a way to drain input for a file descriptor in there, but it might interact badly with fgets/fscanf
A better idea is not to worry about it at all. Unix users are used to having type ahead and what you want would be unexpected behaviour for them.
Drop the need for flushing the input buffer.
OP is on the right track using fgets() rather than scanf() for input, OP should continue that approach with:
char a;
while(a !='y' && a !='Y' && a!='n' && a!='N' ) {
printf("Would you like to run again? (y/n) \n");
if (fgets(kbuffer, sizeof(kbuffer), stdin) == NULL)
Handle_EOForIOerror();
int cnt = sscanf(kbuffer, " %c", &a); // Use %c, not %s
if (cnt == 0)
continue; // Only white-space entered
}
Best to not use scanf() as it tries to handle user IO and parsing in one shot and does neither that well.
Certain present OP's woes stem from fgets() after scanf(" %s", &a); (which is UB as it should be scanf(" %c", &a);. Mixing scanf() with fgets() typically has the problem that the scanf(" %c", &a); leaves the Enter or '\n' in the input buffer obliging the code to want to flsuh the input buffer before the next fgets(). Else that fgets() gets the stale '\n' and not a new line of info.
By only using fgets() for user IO, there need for flushing is negated.
Sample fgets() wrapper
char *prompt_fgets(const char *prompt, char dest, long size) {
fputs(prompt, stdout);
char *retval = fgets(dest, size, stdin);
if (retval != NULL) {
size_t len = strlen(dest);
if (len > 1 && dest[len-1] == '\n') { // Consume trailing \n
dest[--len] = '\0';
}
else if (len + 1 == dest) { // Consume extra char
int ch;
do {
ch == fgetc(stdin);
} while (ch != '\n' && ch != EOF);
}
return retval;
}
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];
}