So, I want to read some input in two integer variables with fscanf, the input must be
INTEGER ONE SPACE INTEGER \n
So for example a file could be like that:
235 190\n
And what I want to do is checking if there is any new line before the first integer or the second, then throw an exception if that's the case:
So basically what you do with fscanf for that case would be just to do like:
FILE *somefile;
[...]
int w, h;
if (fscanf(somefile, "%d%d") == EOF)
return (1);
But this method does not provide checking if there is a new line between the integers
(for example if there is INTEGER NEW_LINE INTEGER it will still read the second)
as it skips all spaces before seeing a digit, so what I managed to do is more close but still wrong:
FILE *somefile;
int w, h;
char check[2];
if (fscanf(somefile, "%d%c%d%c", &w, check, &h, check + 1) == EOF)
return (-1);
if (check[0] != ' ' || check[1] != '\n')
return (-1);
So after I did that I realized that the %c before the %d just reads one character, so if there is a space then a new line between the two, it will continue reading the file wrongly and won't detect an error.
Now I wonder if there is a way to skip all spaces like when using " %c", while knowing if we skipped a \n. Thanks for your help.
PS: I know we can use fgets and strtol but it would be too easy, in this project I can only use fscanf to parse the file.
scanf happily discards leading whitespace to match a %d conversion specifier, which makes this slightly difficult to do. But you can certainly use fgetc (or getchar) to validate a character and then push it back onto the stream for scanf to consume. Something like:
$ cat a.c
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
int c;
int d[2];
c = getchar();
if( 0
||!( c == '+' || c == '-' || isdigit(c))
|| ( c != ungetc(c, stdin) )
|| ( scanf("%d", d) != 1 )
|| ( getchar() != ' ' )
|| ( (c = getchar()) == EOF )
||!( c == '+' || c == '-' || isdigit(c))
|| ( c != ungetc(c, stdin) )
|| ( scanf("%d", d + 1) != 1 )
|| ( getchar() != '\n' )
){
fprintf(stderr, "invalid input!\n");
return EXIT_FAILURE;
}
printf("Read %d %d\n", d[0], d[1]);
return EXIT_SUCCESS;
}
$ gcc a.c
$ printf '5 28\n' | ./a.out
Read 5 28
$ printf '5 28\n' | ./a.out
invalid input!
$ printf ' 5 28\n' | ./a.out
invalid input!
$ printf ' 5 28' | ./a.out
invalid input!
if there is a way to skip all spaces
I can only use fscanf to parse the file.
Let us assume ungetc() is not allowed - which makes things harder.
"%d" happily consumes all (0 or more) leading white-spaces including '\n' without notice.
Use fscanf("%[...]") to find leading white-spaces first. The usual suspects are " \t\n\r\f\v".
// Consume leading whitespaces
// Return
// 1: \n or EOF found
// 0: not found
int EatLeadingWS(FILE *f) {
int count;
char space[2];
while ((count = fscanf("%1[ \t\n\r\f\v]", space)) == 1) {
if (space[0] == '\n') return 1;
}
return count == EOF;
}
Alternative: use "%c" and isspace(), but then we need a way to put non white-spaces back.
Then look for white-spaces before "%d"
int some_int;
if (EatLeadingWS(f) == 0) {
int count;
if ((count = fscanf("%d", &some_int)) == 1) {
printf("int %d found before a \\n\n", some_int);
}
}
Another alternative is to use char buf[100]; fscanf("%99[^\n]", buf) to read most of the line and then parse the string with sscanf(buf, "%d%1[ ]%d" ....
Related
I am supposed to be "fixing" code given to me to make it display the correct number of visible characters in a file (spaces too). The correct number is supposed to be 977. I have never dealt with files before and I don't understand what I need to do to display the correct number.
* Driver Menu System for Homework
* Andrew Potter - Mar 5, 2019 <-- Please put your name/date here
*/
#include <stdio.h>//header file for input/output -
#include <stdlib.h>
#include <ctype.h>
// since you will place all your assigned functions (programs) in this file, you do not need to include stdio.h again!
int menu(void); //prototype definition section
void hello(void);
void countall(void);
int main(void)
{
int selection = menu();
while(selection != 99) {
switch(selection) {
case 1:
hello();
break;
case 2:
countall();
break;
case 3:
break;
case 4:
break;
default:
printf("Please enter a valid selection.\n");
}
selection = menu();
}
return 0;
}
int menu(void) {
int choice;
printf("***************************\n");
printf(" 1. Hello \n");
printf(" 2. Countall\n");
printf(" 3. \n");
printf(" 4. \n");
printf("99. Exit\n");
printf("Please select number and press enter:\n");
printf("***************************\n");
scanf("%d", &choice);
getchar();
return choice;
}
void hello(void) {
printf("Hello, World!!!\n");
}
//*****Andrew 5/1/19*****
#define SLEN 81 /* from reverse.c */
/* original header: int count(argc, *argv[]) */
void countall(void)
{
int ch; // place to store each character as read
FILE *fp; // "file pointer"
long unsigned count = 0;
char file[SLEN]; /* from reverse.c */
/*Checks whether a file name was included when run from the command prompt
* The argument count includes the program file name. A count of 2 indicates
* that an additional parameter was passed
if (argc != 2)
{
printf("Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
* The following uses the second parameter as the file name
* and attempts to open the file
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("Can't open %s\n", argv[1]);
exit(EXIT_FAILURE);
} */
/*************************************
Code from reverse.c included to make the program work from within our IDE
*************************************/
puts("Enter the name of the file to be processed:");
scanf("%s", file);
if ((fp = fopen(file,"rb")) == NULL) /* read mode */
{
printf("count program can't open %s\n", file);
exit(EXIT_FAILURE);
}
/* EOF reached when C realizes it tried to reach beyond the end of the file! */
/* This is good design - see page 573 */
while ((ch = getc(fp)) != EOF)
{
if (isprint(ch)) {
count++;
}
else if (isprint(ch)) {
count++;
}
putc(ch,stdout); // same as putchar(ch);
count++;
}
fclose(fp);
printf("\nFile %s has %lu characters\n", file, count);
}
I expected I would get the correct number of visible characters using the combination of isprint and isspace but I usually get 2086.
The assignment directions are: "Word identifies 977 characters including spaces. Your current countall() believes there are 1043. Make the corrections necessary to your code to count only the visible characters and spaces! (Hint: check out 567 in your textbook.)" Before I edited any code the count was 1043, now i am getting 2020. I need 977.
isprint() returns a Boolean result - zero if the character is not "printable", and non-zero if it is. As such isprint(ch) != '\n'makes no sense. Your complete expression in the question makes even less sense, but I'll come on to that at the end.
isprint() on its own returns true (non-zero) for all printable characters, so you need no other tests. Moreover you increment count unconditionally and in every conditional block, so you are counting every character and some twice.
You just need:
if( isprint(ch) )
{
count++;
}
putc( ch, stdout ) ;
While your code is clearly an incomplete fragment, it is not clear where or how your are reading ch. You need a getc() or equivalent in there somewhare.
while( (ch = getc(fp)) != EOF )
{
if( isprint(ch) )
{
count++;
}
putc( ch, stdout ) ;
}
It is not clear whether you need to count all whitespace (including space, tab and newline) or just "spaces" as you stated. If so be clear that isprint() will match space, but not control characters newline or tab. isspace() matches all these, but should not be counted separately to isprint() because 'space' is in both white-space and printable sets. If newline and tab are to be counted (and less likely; "vertical tab") then:
while( (ch = getc(fp)) != EOF )
{
if( isprint(ch) || isspace(ch) )
{
count++;
}
putc( ch, stdout ) ;
}
Another aspect of C that you seem to misunderstand is how Boolean expressions work. To test a single variable for multiple values you must write:
if( var == x || var == y || var == z )
You have written:
if( var == x || y || z )
which may make sense in English (or other natural language) when you read it out aloud, but in C it means:
if( var == (x || y || z ) )
evaluating (x || y || z ) as either true or false and comparing it to var.
It is probably worth considering the semantics of your existing solution to show why it actually compiles, but produces the erroneous result it does.
Firstly,
isprint(ch) != '\n' || '\t' || '\0'
is equivalent to isprint(ch) != true, for the reasons described earlier. So you increment the counter for all characters that are not printable.
Then here:
isspace(ch) == NULL
NULL is a macro representing an invalid pointer, and isspace() does not return a pointer. However NULL will implicitly cast to zero (or false). So here you increment the counter for all printable characters that are not spaces.
Finally, you unconditionally count every character here:
putc(ch,stdout); // same as putchar(ch);
count++;
So your result will be:
number-of-non-printing-characters +
number-of-printing-characters - number-of-spaces +
total-number-of-characters
which is I think (2 x file-length) - number-of-spaces
Finally note that if you open a text file that has CR+LF line ends (conventional for text files on Windows) in "binary" mode, isspace() will count two characters for every new-line. Be sure to open in "text" mode (regardless of the platform).
From isprint():
A printable character is a character that occupies a printing position on a display (this is the opposite of a control character, checked with iscntrl).
and
A value different from zero (i.e., true) if indeed c is a printable character. Zero (i.e., false) otherwise.
So that function should be sufficient. Please note that you have to make sure to feed all these is...() functions from <ctype.h> unsigned values. So if you use it with a value of uncertain origin, better cast to char unsigned.
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char const *filename = "test.txt";
FILE *input = fopen(filename, "r");
if (!input) {
fprintf(stderr, "Couldn't open \"%s\" for reading. :(\n\n", filename);
return EXIT_FAILURE;
}
long long unsigned count = 0;
for (int ch; (ch = fgetc(input)) != EOF;) {
if (isprint(ch))
++count;
}
fclose(input);
printf("Count: %llu\n\n", count);
}
If I wasn't lucky enough to guess which characters you want to be counted, have a look at ctype.h, there is a table.
if ((ch == '\t') || isprint(ch))
count++;
If you want to handle tabs differently (maybe to count how many spaces they use):
if (ch == '\t') {
/* Do smth */
} else if (isprint(ch)) {
count++;
}
This should be enough.
I want read data from console and output to Text file with reserve of N character per variable of structure type.
The Text file is similar to:
1 111 1 Peter
22 22 2 John Lays
3 3 3 Anne Belgs
I do not know if I'm using the most correct functions.
Also I can not read ("carro.name") more than 1 word (example: John Lays)
struct estruturaCarro {
int id, potencia, avariado;
char name[11];
} carro;
...
//Read data to Text File:
...
printf("\n ID......:"); scanf("%d", &carro.id);
printf("\n Potencia:"); scanf("%d", &carro.potencia);
printf("\n Avariado:"); scanf("%d", &carro.avariado);
printf("\n NAME:"); scanf("%10[0-9a-zA-Z ]", carro.name); // or scanf("%[^\n]s",...)
fprintf(fp, "%-2d %-3d %-1d %-10s \n\n", carro.id, carro.potencia, carro.avariado, carro.name);
...
//Show File Text data:
...
int registos=0;
while(1)
{
fscanf(fp, "%d %d %d %-10s", &carro.id, &carro.potencia, &carro.avariado, carro.name);
if(feof(fp)){ break; }
printf("%-2d %-3d %-1d %-10s\n", carro.id, carro.potencia, carro.avariado, carro.name);
registos++;
}
printf("\nCarros=%d", registos);
As you say in your question you cannot use scanf to read a complex name including spaces.
But before to search how to do it is needed to decide what to do.
Probably you do not want to memorize the extra spaces at the beginning and at the end (including the newline), and probably a name must not be empty.
But what about inside a complex name ? If the user enter John Lays do you save the name with the two spaces or you want to simplify to have only one ? Do you have to manage other special character like '-' (are John - Lays / John- Lays / John -Lays read as John-Lays ?).
What to do if the input string is longer than 10 characters ? Just to stop to read letting the rest for the next read or to bypass up to a newline ? Because you print a message before each input you clearly want an input per line and the rest of the line must be bypassed.
If you do not want to read the string as it is enter the best way is probably to write your own read string function.
You also have to decide what to do if the user do not enter a number for ID or Potencia or Avariado, currently you do not even detect the error, this is not a good way. So in that case do you abort all (exit program), or you redo the read ? Probably you prefer to read again, for that you need to bypass the invalid input, but what that means, to bypass all up to a newline ?
For instance :
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* read an int memorizing its value in v,
return 0 in case of EOF else a non null value */
int readInt(const char * msg, int * v)
{
for (;;) {
fputs(msg, stdout);
if (scanf("%d", v) == 1)
return 1;
/* not a number or EOF, bypass all up to \n */
int c;
while ((c = fgetc(stdin)) != '\n')
if (c == EOF)
return 0;
puts("invalid value"); /* message may be also get in argument */
}
}
/* read a string up to a \n
remove extra spaces at the beginning and end
simplify internal multiple spaces
accept any character and do not manage in a special way characters like like '-'
a non empty string must be read
read at most sz-1 characters in s then place the null character (as fgets), sz must be > 1
if the line too long bypass the rest of the input up to \n
return 0 in case of EOF else a non null value */
int readStr(const char * msg, char * s, size_t sz)
{
fputs(msg, stdout);
/* read the first char bypassing spaces including \n */
if (scanf(" %c", s) == 0)
// EOF
return 0;
size_t index = 1;
int c;
sz -= 1;
while (index != sz) {
c = fgetc(stdin);
if ((c == EOF) || (c == '\n'))
break;
if (!isspace(c))
s[index++] = c;
else if (s[index - 1] != ' ')
s[index++] = ' ';
}
s[(s[index - 1] != ' ') ? index : index-1] = 0;
// bypass possible rest of the line
while ((c != EOF) && (c != '\n'))
c = fgetc(stdin);
return 1;
}
/* ******************* */
struct estruturaCarro {
int id, potencia, avariado;
char name[11];
} carro;
int main()
{
do {
if (!readInt("\n ID......:", &carro.id) ||
!readInt("\n Potencia:", &carro.potencia) ||
!readInt("\n Avariado:", &carro.avariado) ||
!readStr("\n NAME:", carro.name, sizeof(carro.name))) {
puts("EOF");
return -1;
}
else
printf("%-2d %-3d %-1d '%-10s' \n\n", carro.id, carro.potencia, carro.avariado, carro.name);
} while (strcmp(carro.name, "end"));
return 0;
}
Compilation and execution:
pi#raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall r.c
pi#raspberrypi:/tmp $ ./a.out
ID......:aze
invalid value
ID......:qsd
invalid value
ID......:1
Potencia:2
Avariado:3
NAME:aze u iiiiiiiiiiiiiiiiii
1 2 3 'aze u iiii'
ID......:11
Potencia:22
Avariado:0
NAME: end
11 22 0 'end '
pi#raspberrypi:/tmp $
When you read in your file and supposing it was produced doing fprintf(fp, "%-2d %-3d %-1d %-10s", ...) :
char line[21]; /* each line has 20 characters newline included */
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%d %d %d", &carro.id, &carro.potencia, &carro.avariado) != 3)
/* abnormal case, invalid file */
break; /* anything else you want to do */
/* the string starts at the index 9 and has 10 characters out of the newline */
memcpy(carro.name, line + 9, 10);
carro.name[10] = 0;
/* ... */
}
note the name have spaces at the end if its length is less than 10 characters
Or you can read in a way similar to the previous on stdin.
I need the program to exit the while loop if the user presses enter without entering any float value. Thanks!
printf("Enter scores\n”);
float scores[10];
int n=0;
while (n<10){
scanf("%f", &scores[n]);
n++;
if (THE USER PRESSES ENTER WITHOUT ENTERING ANYTHING){break;}
}
You can use fgets() to read a line of input through the newline character into a buffer, and then use sscanf() to parse the contents of the buffer. The problem with using scanf() for this is that most conversion specifiers, and in particular the %f conversion specifier, skip leading whitespace, including newlines. So, if you try to give an empty line to scanf(), the function will continue to wait for input until you enter a non-white-space character.
The code below adapts this technique to your code. The variable n has been changed to a size_t type variable, as this is an unsigned type guaranteed to be able to hold any array index. Furthermore, note that both fgets() and sscanf() return values that should be checked. The fgets() function returns a null pointer if there is an error, and the code below prints an error message and exits if this occurs. The sscanf() function returns the number of successful conversions made, and this value can be used to make sure that the input is as expected. When the user enters a blank line, or a line with no leading floating point value (leading white-space is OK), zero is returned, and the input loop is escaped.
I added some code to display the values entered into the array.
#include <stdio.h>
#include <stdlib.h> // for exit()
int main(void)
{
float scores[10];
char buffer[100];
size_t n = 0;
printf("Enter scores\n");
while (n < 10){
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
fprintf(stderr, "Error in fgets()\n");
exit(EXIT_FAILURE);
}
if (sscanf(buffer, "%f", &scores[n]) == 1) {
++n;
} else {
break;
}
}
for (size_t i = 0; i < n; i++) {
printf("scores[%zu] = %f\n", i, scores[i]);
}
return 0;
}
Sample interaction:
Enter scores
3.8
3.6
2.9
3.4
scores[0] = 3.800000
scores[1] = 3.600000
scores[2] = 2.900000
scores[3] = 3.400000
Separate input of user text from parsing.
Read the line of user input as a string;
char buffer[80];
if (fgets(buffer, sizeof buffer, stdin) == NULL) Handle_EOF();
Now, parse the string using sscanf(), strtod(), etc.
if (sscanf(buffer, "%f", &scores[n]) == 1) Handle_Successful_Float_Input(scores[n]);
else if (buffer[0] == '\n') Handle_Empty_Line();
else Handle_Everything_Else(buffer);
fgets is the better route but if scanf must be used, newline can be detected by scanning a character. If the character is not a newline, replace it in the input with ungetc and then scan the float.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE 10
int main ( void) {
char i = '\0';
int n = 0;
int result = 0;
float scores[SIZE] = { 0.0f};
printf ( "enter scores\n");
while ( n < SIZE && ( scanf("%c",&i) == 1)) {//scan a character
if ( i == '\n') {
break;//newline so leave loop
}
else {
ungetc ( i, stdin);//replace the character in input stream
}
if ( ( result = scanf ( "%f", &scores[n])) == 1) {//scan a float
printf ( " score[%d] entered as %f\n", n, scores[n]);
n++;
}
if ( result == 0) {
printf ( "please enter a number\n");//could not scan the input as a float
}
while ( ( result = getchar ( )) != '\n') {//clean the input stream
if ( result == EOF) {
fprintf ( stderr, "problem EOF\n");
return 1;
}
}
printf ( "enter score[%d]\n", n);
}
return 0;
}
I thought . you want to check that if an integer is assigned a value or not ?
Actually you have to initialize the variable otherwise it will contain whatever happen at that memory location unless it is declared as global. If you are not getting then check
this might help you with your question
We know that scanf returns a negative value if nothing of the defined type is fetched from the input.
So:
printf("Enter scores\n”);
float scores[10];
int n=0;
while (n<10){
if(scanf("%f\n", &scores[n]) < 0) printf("Error! Error!");
n++;
}
See http://www.cplusplus.com/reference/cstdio/scanf/
I have file that will contain either two numbers with variable whitespace in between them or just a blank line. I need to know when the input is just a blank line, and then to not assign into those variables using fscanf.
Doing:
FILE *pFile = fopen (my_file, "r");
if (pFile == NULL) perror ("Error opening file");
int succ = 1, num1 = 0, num2 = 0;
while (succ != EOF)
{
succ = fscanf(pFile, "%d %d", &num1, &num2);
}
Works very well for detecting all of the numbers properly, but not the newline.
I tried:
fscanf(pFile, "%d %d %*[^\n]", &num1, &num2);
But it always properly assigns to both numbers. I want to be able to make a switch statement to do other logic based on if succ is 2 (indicating both numbers were assigned too) or 0 (indicating a blank line).
I'd prefer avoiding getline if possible; seems like that would be inefficient to use iostream stuff mixed with stdio functions.
I tried this guys suggestion, didn't work out, although logically I thought it would work, it didn't.
Honestly, I don't even understand why something like
"%d %d \n"
Wouldn't work. It's simple... scan the file until a newline, return back how many assignments were done, that's it!
"%d %d \n" will not work to achieve OP goals as any white-space directive consumes any white-space. Using ' ' or '\n' make no difference they both consume 0 or more white-spaces. (expect in '[]' specifiers)
OP wants to detect a '\n' and fscanf() is not a good choice. fgets() is better.
#define N (100 /* longest line */)
char buf[N];
while (fgets(buf, sizeof buf, pFile) != NULL) {
int cnt = sscanf("%d%d",&num1, &num2);
switch (cnt) {
case 0: Handle_NoNumbers(); break;
case 1: Handle_1Number(); break;
case 2: Handle_Success(); break;
}
}
The '%d' in fscanf(stream, "%d", &num) specifies to consume all leading white-space before a number without regard to '\n' or ' ', etc.
If code must use fscanf(), then code needs to consume leading white-space before calling fscanf(... "%d") in a way to distinguish '\n' from ' '.
// Consume white space except \n and EOF
int consume_ws(FILE *pFile) {
do {
int c = fgetc(pFile); // could use fscanf(...%c...) here
if (c == '\n' || c == EOF) return c;
} while (isspace(c));
ungetc(c, pFile); // put the char back
return 0;
}
...
while(1) {
int num[2];
int i;
for (i = 0; i < 2; i++) {
if (consume_ws(pFile)) {
Handle_ScantData(); // Not enough data
return;
}
if (1 != fscanf(pFile, "%d", &num[i]) {
Handle_NonnumericData();
return;
}
}
int ch = consume_ws(pFile);
if (ch == 0) Handle_ExtraData();
// Else do something with the 2 numbers
if (ch == EOF) return;
}
If I input 5 5 at the terminal, press enter, and press enter again, I want to exit out of the loop.
int readCoefficents(double complex *c){
int i = 0;
double real;
double img;
while(scanf("%f %f", &real, &img) == 2)
c[i++] = real + img * I;
c[i++] = 1 + 0*I; // most significant coefficient is assumed to be 1
return i;
}
Obviously, that code isn't doing the job for me (and yes, I know there is a buffer overflow waiting to happen).
scanf won't quit unless I type in a letter (or some non-numeric, not whitespace string). How do I get scanf to quit after reading an empty line?
Use fgets to read console input:
int res = 2;
while (res == 2) {
char buf[100];
fgets(buf, sizeof(buf), stdin);
res = sscanf(buf, "%f %f", &real, &img);
if (res == 2)
c[i++] = real + img * I;
}
c[i++] = 1 + 0*I; // most significant coefficient is assumed to be 1
return i;
The specific problem you're having is that a scanf format string of %f will skip white space (including newlines) until it finds an actual character to scan. From the c99 standard:
A conversion specification is executed in the following steps:
- Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a '[', 'c', or 'n' specifier.
and, elsewhere, describing isspace():
The standard white-space characters are the following: space ' ', form feed '\f', new-line '\n', carriage return '\r', horizontal tab '\t', and vertical tab '\v'.
Your best bet is to use fgets to get the line (and this can be protected from buffer overflow very easily), then use sscanf on the resultant line.
The scanf function is one of those ones you should look at very warily. The following piece of code is one I often use to handle line input:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
// Test program for getLine().
int main (void) {
int rc;
char buff[10];
rc = getLine ("Enter string> ", buff, sizeof(buff));
if (rc == NO_INPUT) {
// Extra NL since my system doesn't output that on EOF.
printf ("\nNo input\n");
return 1;
}
if (rc == TOO_LONG) {
printf ("Input too long [%s]\n", buff);
return 1;
}
printf ("OK [%s]\n", buff);
return 0;
}
Testing it with various combinations:
pax> ./prog
Enter string>[CTRL-D]
No input
pax> ./prog
Enter string> a
OK [a]
pax> ./prog
Enter string> hello
OK [hello]
pax> ./prog
Enter string> hello there
Input too long [hello the]
pax> ./prog
Enter string> i am pax
OK [i am pax]
What I would do is to use this function to get a line safely, then simply use:
sscanf (buffer, "%f %f", &real, &img)
to get the actual values (and check the count).
In fact, here's a complete program which is closer to what you want:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
int main (void) {
int i = 1, rc;
char prompt[50], buff[50];
float real, imag;
while (1) {
sprintf (prompt, "\nEnter real and imaginary for #%3d: ", i);
rc = getLine (prompt, buff, sizeof(buff));
if (rc == NO_INPUT) break;
if (*buff == '\0') break;
if (rc == TOO_LONG) {
printf ("** Input too long [%s]...\n", buff);
}
if (sscanf (buff, "%f %f", &real, &imag) == 2) {
printf ("Values were %f and %f\n", real, imag);
i++;
} else {
printf ("** Invalid input [%s]\n", buff);
}
}
return 0;
}
along with a test run:
pax> ./testprog
Enter real and imaginary for # 1: hello
** Invalid input [hello]
Enter real and imaginary for # 1: hello there
** Invalid input [hello there]
Enter real and imaginary for # 1: 1
** Invalid input [1]
Enter real and imaginary for # 1: 1.23 4.56
Values were 1.230000 and 4.560000
Enter real and imaginary for # 2:
pax> _
There's a way to do what you want using just scanf:
int readCoefficents(double complex *c) {
int i = 0;
double real;
double img;
char buf[2];
while (scanf("%1[\n]", buf) == 0) { // loop until a blank line or EOF
if (scanf("%lf %lf", &real, &img) == 2) // read two floats
c[i++] = real + img * I;
scanf("%*[^\n]"); // skip the rest of the line
scanf("%*1[\n]"); // and the newline
}
c[i++] = 1 + 0*I; // most significant coefficient is assumed to be 1
return i;
}
If the user only enters 1 float on a line, it will read the next line for the second value. If any random garbage is entered, it will skip up to a newline and try again with the next line. Otherwise, it will just go on reading pairs of float values until the user enters a blank line or an EOF is reached.
re PAXDIABLO solution: it does not work properly with EMPTY line entered by user, so this line shall be added in your getLine() function
if (strlen(buff) <= 1) return NO_INPUT;
after the line:
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
So it will become :
...
if (strlen(buff) <= 1) return NO_INPUT;
if (fgets (buff, sz, stdin) == NULL) return NO_INPUT;
....
Instead of
while(scanf("%f %f", &real, &img) == 2)
try
while(scanf("%f %f%*c", &real, &img) == 2)
scanf("%f%*c", &myfloat); // will read a float and all eventual characters after it