fgets not doing as I expect.

B

Ben Bacarisse

Andrew McMeikan said:
William said:
I wanted to limit how many chars I read in, but the code below instead of stopping at
7 chars will happily read 30 or 40 car lines and spit them out. Not what I expected.
Any pointers?
#include <stdio.h>

int main(void){
char line [100];
while (NULL!=fgets(line,8,stdin))
{
printf("%s",line);
}
return 0;
}

How could you expect this program to do anything other
than what you describe? Each pass through the loop
it reads up to 7 chars from stdin and prints them.
Sometimes, it reads less than 7 chars, but there's
no way for you to tell in the output since
you can't distinguish between
"abcdefgh" and "abcdefgh". (in the first case,
I typed "abc", then "def", then "gh", but in
the second I typed "abcd", then "efgh".) What
behavior did you expect?

I expected that if I typed 123456789 I would get 1234567 out.
I threw in a \n in the printf and it now makes some sense.

Still not behaving how I hoped having the 89 spill over is not what
I wanted, just wanted a nice safe way of inputing size limited
fields.

It is doing that. What you also seemed to want was to throw away any
input that remains on the line. This is quite a separate issue. The
usual way of to write a function like:

void discard_input(FILE *fp)
{
int c;
while ((c = fgetc(fp)) != '\n' && c != EOF);
}

though you might prefer one that returns an indication of why it
finished. Of course, you must only use this function of the input you
get does not already include a '\n'.

A "bigger picture" description of what you are trying to do would help
you get better answers.
 
B

Barry Schwarz

On Fri, 26 Dec 2008 23:53:55 -0900, Andrew McMeikan

snip
void getstr(char *str, int l){
int i;

fgets(str,l,stdin);
for (i = 0; i < l; i++)
{
if (str=='\n')
{
str='\0';


Since there can be at most one "current" '\n' in the string, you can
return once you replace it and not check the remaining characters in
the string.

snip
 
B

Barry Schwarz

On Fri, 26 Dec 2008 22:36:36 -0900, Andrew McMeikan


snip
I am writing some code that needs user input to fill in some structure fields in an
array and I wanted to make sure that it was done safely.

The scanf below for qty seems to leave a \n that clobbers location. Been a while

Yes it does. The numeric formats (%d etc) skip any initial white
space but then stop at (not after) the first white space that follows
the number. '\n' is a white space character and is left in the
buffer.

You can remove any residual characters in the stream by executing a
getc loop that terminates only upon receiving a '\n' or reaching end
of file. Several have been posted in this group. (The two feof loops
in your 192 line post (12/27 12:53) don't check for both. By the way,
feof() is reactive, not predictive.)

Another approach is to avoid scanf altogether. Read the data into a
temporary character buffer with fgets and use strtoul to convert it to
its equivalent numeric value. This has the additional advantage that
the strto_ functions provide for error detection.
since I have done serious coding, I don't remember this many problems before :)

void addpart(PART p[],int *n){

printf("Adding a part.\n"
"Please enter a part number:");
fgets(p[*n].part,sizeof(p[0].part),stdin);
printf("Please enter part description:");
fgets(p[*n].description,sizeof(p[0].description),stdin);
printf("Please enter quantity:");
scanf("%hu",&p[*n].qty);
printf("Please enter location:");
fgets(p[*n].location,5,stdin);
(*n)++;
}
 
K

Keith Thompson

Andrew McMeikan said:
I wanted to limit how many chars I read in, but the code below
instead of stopping at 7 chars will happily read 30 or 40 car lines
and spit them out. Not what I expected. Any pointers?

#include <stdio.h>

int main(void){
char line [100];

while (NULL!=fgets(line,8,stdin))
{
printf("%s",line);
}

return 0;
}

fgets is doing exactly what it's supposed to do. To understand what
it's doing and how it's doing it, try changing your printf line to:

printf("[%s]",line);

so you can see each individual string returned by fgets.

If fgets has read an incomplete line, the resulting string will not
end with a '\n' character.
 
C

CBFalconer

Andrew said:
I wanted to limit how many chars I read in, but the code below
instead of stopping at 7 chars will happily read 30 or 40 car
lines and spit them out. Not what I expected. Any pointers?

Yes. Start by reading the description of fgets. Then also correct
your postings so that lines do not exceed 72 chars (67 is better).

7.19.7.2 The fgets function
Synopsis
[#1]
#include <stdio.h>
char *fgets(char * restrict s, int n,
FILE * restrict stream);

Description

[#2] The fgets function reads at most one less than the
number of characters specified by n from the stream pointed
to by stream into the array pointed to by s. No additional
characters are read after a new-line character (which is
retained) or after end-of-file. A null character is written
immediately after the last character read into the array.

Returns

[#3] The fgets function returns s if successful. If end-of-
file is encountered and no characters have been read into
the array, the contents of the array remain unchanged and a
null pointer is returned. If a read error occurs during the
operation, the array contents are indeterminate and a null
pointer is returned.
 
A

Andrew McMeikan

I wanted to limit how many chars I read in, but the code below instead of stopping at
7 chars will happily read 30 or 40 car lines and spit them out. Not what I expected.
Any pointers?

cya, Andrew...

#include <stdio.h>

int main(void){
char line [100];

while (NULL!=fgets(line,8,stdin))
{
printf("%s",line);
}

return 0;
}
 
A

Andrew McMeikan

William said:
I wanted to limit how many chars I read in, but the code below instead of stopping at
7 chars will happily read 30 or 40 car lines and spit them out. Not what I expected.
Any pointers?
#include <stdio.h>

int main(void){
char line [100];

while (NULL!=fgets(line,8,stdin))
{
printf("%s",line);
}

return 0;

}

How could you expect this program to do anything other
than what you describe? Each pass through the loop
it reads up to 7 chars from stdin and prints them.
Sometimes, it reads less than 7 chars, but there's
no way for you to tell in the output since
you can't distinguish between
"abcdefgh" and "abcdefgh". (in the first case,
I typed "abc", then "def", then "gh", but in
the second I typed "abcd", then "efgh".) What
behavior did you expect?

I expected that if I typed 123456789 I would get 1234567 out.
I threw in a \n in the printf and it now makes some sense.

Still not behaving how I hoped having the 89 spill over is not what I wanted, just
wanted a nice safe way of inputing size limited fields.

Thanks for your help.

cya, Andrew...
 
A

Andrew McMeikan

Ben said:
Andrew McMeikan said:
William said:
I wanted to limit how many chars I read in, but the code below instead of stopping at
7 chars will happily read 30 or 40 car lines and spit them out. Not what I expected.
Any pointers?
#include <stdio.h>

int main(void){
char line [100];
while (NULL!=fgets(line,8,stdin))
{
printf("%s",line);
}
return 0;
}

How could you expect this program to do anything other
than what you describe? Each pass through the loop
it reads up to 7 chars from stdin and prints them.
Sometimes, it reads less than 7 chars, but there's
no way for you to tell in the output since
you can't distinguish between
"abcdefgh" and "abcdefgh". (in the first case,
I typed "abc", then "def", then "gh", but in
the second I typed "abcd", then "efgh".) What
behavior did you expect?
I expected that if I typed 123456789 I would get 1234567 out.
I threw in a \n in the printf and it now makes some sense.

Still not behaving how I hoped having the 89 spill over is not what
I wanted, just wanted a nice safe way of inputing size limited
fields.

It is doing that. What you also seemed to want was to throw away any
input that remains on the line. This is quite a separate issue. The
usual way of to write a function like:

void discard_input(FILE *fp)
{
int c;
while ((c = fgetc(fp)) != '\n' && c != EOF);
}

though you might prefer one that returns an indication of why it
finished. Of course, you must only use this function of the input you
get does not already include a '\n'.

A "bigger picture" description of what you are trying to do would help
you get better answers.

I am writing some code that needs user input to fill in some structure fields in an
array and I wanted to make sure that it was done safely.

The scanf below for qty seems to leave a \n that clobbers location. Been a while
since I have done serious coding, I don't remember this many problems before :)

void addpart(PART p[],int *n){

printf("Adding a part.\n"
"Please enter a part number:");
fgets(p[*n].part,sizeof(p[0].part),stdin);
printf("Please enter part description:");
fgets(p[*n].description,sizeof(p[0].description),stdin);
printf("Please enter quantity:");
scanf("%hu",&p[*n].qty);
printf("Please enter location:");
fgets(p[*n].location,5,stdin);
(*n)++;
}
 
A

Andrew McMeikan

Thanks everyone, it is now doing what I want enough that I can make progress now.
Below is code so far if your interested.

#include <stdio.h>
#include <stdbool.h>
/************************************************
* Program: Parts management *
* File name: parts.c *
* Author: Andrew McMeikan *
* Created: 25/12/08 *
* Updated: 26/12/08 *
* *
* Purpose: To maintain a database of *
* electronic parts *
************************************************/

#define MAXNUM 10000

typedef struct {
unsigned long tracking;
char location[5];
char otherlocation[5];
char part[25];
char description[160];
char picture[80];
char datasheet[80];
unsigned short cost;
unsigned short qty;
unsigned short Reorder;
bool onorder;
bool counted;
bool emptylocation;
unsigned short noncount;
char alternate1[25];
char alternate2[25];
char supplier1[80];
char supplier1code[25];
char supplier2[80];
char supplier2code[25];

} PART;


void browseparts(PART p[],int *n);
void getstr(char *str, int l);
int dataread(PART p[],char filename[],int *n);
int dump(PART p[],char filename[], int *n);
void addpart(PART p[],int *n);



int main(void)
{

PART parts[MAXNUM];
int num;
char menuchoice;

dataread(parts,"parts.dat",&num);

do{
printf("\x1B[2J \x1B[H ");
printf("Welcome to the Parts Manager\n");

printf("Number of records is %d\n",num);
printf("\n"
"1. Search for part.\n"
"2. Add part to system.\n"
"3. Consume a part.\n"
"4. Perform a stocktake.\n"
"5. Check for re-ordering.\n"
"6. Edit part information.\n"
"7. Browse for parts.\n"
"8. Utility menu.\n\n"
"9. Quit.\n");

printf("\n\nChoice?:");
scanf("%c",&menuchoice);


switch (menuchoice)
{
case '1': break;
case '2': addpart(parts,&num); break;
case '3': break;
case '4': break;
case '5': break;
case '6': break;
case '7': browseparts(parts,&num); break;
case '8': break;

default: printf("\a");
}


}while (menuchoice!='9');

dump(parts,"parts.dat",&num);


return 0;
}

void browseparts(PART p[],int *n){
int i;
for (i = 0; i < *n; i++)
{
printf("part code :%s\n descr :%s\n qty :%d\nLocation :%s\n\n"
,p.part,p.description,p.qty,p.location);

}
do{}
while('x'!=getc(stdin));

}

void addpart(PART p[],int *n){

printf("Adding a part.\n"
"Please enter a part number:");
if (!feof(stdin)) {
getc(stdin);
}
getstr(p[*n].part,sizeof(p[0].part));
printf("Please enter part description:");
getstr(p[*n].description,sizeof(p[0].description));
printf("Please enter quantity:");
scanf("%hu",&p[*n].qty);
printf("Please enter location:");
if (!feof(stdin)) {
getc(stdin);
}
getstr(p[*n].location,sizeof(p[0].location));
(*n)++;
}


void getstr(char *str, int l){
int i;

fgets(str,l,stdin);
for (i = 0; i < l; i++)
{
if (str=='\n')
{
str='\0';
}

}

}


int dataread(PART p[],char filename[],int *n){

FILE *data;
int i;

data=fopen(filename,"r");

if (data==NULL)
{
printf("Sorry I encountered an error trying to open %s\n",filename);
perror("");
return 1;
}
i=fread(&p,sizeof(p[0]),MAXNUM,data);

*n=i;
return 0;
}


int dump(PART p[],char filename[], int *n){
FILE *dumpfile;

dumpfile=fopen(filename,"w");
if (dumpfile!=NULL)
{
printf("File %s opened for writing.\n",filename);
}
else
{
printf("Sorry I encountered an error trying to open %s\n",filename);
return 1;
}

fwrite(p,sizeof(p[0]),*n,dumpfile);

fclose(dumpfile);
return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top