While loop format in C [duplicate] - c

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
comma separated expression in while loop in C
Hi All,
Has anybody ever encountered this format of while loop in C?
If yes, what is the syntax? I am not able to understand this. Please help.
Regards
kingsmasher1
while(printf("> "), fgets(str, 100, stdin), !feof(stdin))
{
}

This is an excellent example of evil code. Do not write code like this. It is hard to read and debug. It is useful only in obfuscated C contests or to otherwise demonstrate how clever you are. In some jurisdictions, it may render you liable to charges of compiler abuse. Using code like this may cause subsequent maintainers to hunt you down and LART you with extreme prejudice. In extreme cases, Randall Munroe may make fun of you.

Your loop is equivalent to:
do {
printf("> ");
fgets(str, 100, stdin);
} while(!feof(stdin));

This is an instance of the Comma Operator: http://en.wikipedia.org/wiki/Comma_operator Two instances, actually.
The comma operator evaluates the expression on the left hand side of the comma first, then the one on the right, returning the latter as the value of the entire expression.
So in this case, it's equivalent to
do
{
printf("> ");
fgets(str, 100, stdin);
} while (!feof(stdin));
I don't recommend writing obtuse code like this. The comma operator is rarely used - typically in macros which should act like an expression but actually execute a sequence of operations.

That's an abuse of the comma operator.
What it does is
while(printf("> "), fgets(str, 100, stdin), !feof(stdin))
it evaluates each of the expressions separated by the comma operator and discards the values of all but the rightmost one. It uses the value of the right most one as the value of the whole expression. So, you have
while (expression) /*...*/;
and, your expression is
printf("> "), fgets(str, 100, stdin), !feof(stdin)
That expression:
prints a greater than sign and a space evaluating to 2; it discards the 2
reads at most 100 chars from stdin into str and evalutes to either str or NULL if there was an error. That value (str or NULL) is discarded
it sees if the stream stdin is in an end-of-file condition and the value is the value of the whole expression (1 if stdin is in end-of-file condition; 0 otherwise)

Related

fscanf comma seperated in C90 [duplicate]

I have the following input:
AG23,VU,Blablublablu,8
IE22,VU,FooBlaFooBlaFoo,3
and so on...
I want it to "parse" with scanf() using some code like this:
char sem[5];
char type[5];
char title[80];
int value;
while(scanf("%s,%s,%s,%d", sem, type, title, &value) == 4) {
//do something with the read line values
}
But the execution of the code gives me: illegal instruction
How would you read a comma-separated file like this?
The comma is not considered a whitespace character so the format specifier "%s" will consume the , and everything else on the line writing beyond the bounds of the array sem causing undefined behaviour. To correct this you need to use a scanset:
while (scanf("%4[^,],%4[^,],%79[^,],%d", sem, type, title, &value) == 4)
where:
%4[^,] means read at most four characters or until a comma is encountered.
Specifying the width prevents buffer overrun.
you can use
scanf("%d%*c"); // to suppress any character you want to skip taking input
suppose scanf("%d%*c%d",&a,&b); // i/p is 31,42 %*is used for suppression
o/p: 3142
it may be any character / , . .......
The problem that you are having is because when you say
scanf("%s,%s,%s,%d", sem, type, title, &value)
what happens is that you are trying doing is that you are fitting all the line into the first string which is just 5 characters. Therefore the sem[5] overflows, and soes all sorts of funny things. To avoid this problem, I tried using the expression %[^,], but it is not quite working. The best bet is to use something like
while(scanf("%s%c%s%c%s%c%d", sem, &ch, type, &ch, title, &ch, &value) != EOF)
Then you can just discard the ch. However bear in mind that is better to use other functions to reading input such as getchar(), and things like that, which are much faster and safer in some sense.

Why is this a valid scanf statement to break out of a while loop?

Why is this a valid line of code to break out of an infinite while loop?
if (scanf("%s", word) != 1) break;
if (scanf("%s", word) != 1) break;
scanf returns the number of items successfully consumed. This value is used as the left hand operand inside of the expression. Thus, this expression is perfectly valid.
In the following example this value shall be 1 if no I/O error occurred and a string was successfully converted because there is only one item to consume.
I guess this if statement is part of a loop whose intention is to read subsequent words from the input until it encounters an EOF state for stdin or any redirected file used as input because the condition is only then evaluated to true (and with that to break out of the surrounding loop) if EOF or another I/O error has happen as scanf() returns 0 in this case.
This shall give you an insight of how this if statement is to be evaluated and interpreted.
The mentioned break statement and its guard is valid but it's lying. Consider the loop
while (1) {
...
}
According to the rules of structured programming the loop should never exit, that is unless the program exits. Rather than using a break statement, a properly structured program should use the return value from the function scan as the loop guard, like this:
tokenCount = scanf("%s", word);
while (tokenCount == 1) {
...
tokenCount = scanf("%s", word);
}
It's also easier to reason about the correctness of a program if expressions do not have side effects; that's why the return value is stored in a variable (with a meaningful name).

how to skip all the first spaces in a string using shortcuts in C

I wanna to skip all kind of spaces in my string.
I know how to do it the "traditional" way.
I'm not totally familiar with the shortcuts, so I'd like to know why this isn't working:
(*str < 33) ? *str++ : 0;
gcc tells me that *str++ is unused which I don't get since I'm moving to the next char if the <33 condition is satisfied.
Obviously, I misinterpreted something, could someone tell me what THANKS :O)
The ? construct is used to evaluate an expression; unless you have this inside of a larger statement, the value of this expression is what is "unused".
As has been commented, if you are trying to decide whether or not to increment str, you should be using an if statement.

What does the following bit of code mean/do?

I think this is an odd way of writing something in C, but I know I've seen it before. I am unable to recall what this line does. THis is the start of a long loop, so how does it work exactly?
if(ret_val = fgets(st, n, stdin));
How does this if statement work?
The semicolon at the end of that statement makes the if statement completely useless.
After removing the semicolon, that if statement is extremely bad form, and should be either rewritten as
if ( (ret_val = fgets(st, n, stdin)) != NULL )
{
}
or
ret_val = fgets(st, n, stdin);
if ( ret_val )
{
}
The reason it's bad form is that it's a common error to mistakenly use an assignment operator = where the equality operator == was intended. The two forms shown above make it clear that the assignment was intentional, and not just a typo.
From this site
The C library function char *fgets(char *str, int n, FILE *stream) reads a line from the specified stream and stores it into the string pointed to by str. It stops when either (n-1) characters are read, the newline character is read, or the end-of-file is reached, whichever comes first.
Several things to consider;
(1) the return value of fgets:
on success, fgets returns str
on success, if end-of-file is encountered, eof indicator is set
on success, if end-of-file is encountered, and no character is read NULL is returned
if a read error occures, NULL is returned
(2) with an assignment statement, the value of the left-hand side is returned. This is standard behaviour, section 6.5.16 of the C99 standard: " An assignment expression has the value of the left operand after the assignment"
So, in the first two cases above, the assignment expression returns a pointer to the string, and the last two cases the assignment expression returns NULL. Thus, in the first two cases the body of the if-clause is executed, and in the last two cases if body of the if-clause is not taken.
So the bottom line is that the line of code that the op posted is equivalent to these two lines:
ret_val = fgets(st, n, stdin);
if(ret_val);
Hope this helps.

Flushing stdin after every input - which approach is not buggy?

After Mark Lakata pointed out that the garbage isn't properly defined in my question I came up with this. I'll keep this updated to avoid confusions.
I am trying to get a function that I can call before a prompt for user input like printf("Enter your choice:); followed a scanf and be sure that only the things entered after the prompt would be scanned in by scanf as valid input.
As far as I can understand the function that is needed is something that flushes standard input completely. That is what I want. So for the purpose of this function the "garbage" is everything in user input i.e. the whole user input before that user prompt.
While using scanf() in C there is always the problem of extra input lying in the input buffer. So I was looking for a function that I call after every scanf call to remedy this problem. I used this, this, this and this to get these answers
//First approach
scanf("%*[^\n]\n");
//2ndapproach
scanf("%*[^\n]%*c");
//3rd approach
int c;
while((c = getchar()) != EOF)
if (c == '\n')
break;
All three are working as far as I could find by hit-and-trial and going by the references. But before using any of these in all of my codes I wanted to know whether any of these have any bugs?
EDIT:
Thanks to Mark Lakata for one bug in 3rd. I corrected it in the question.
EDIT2:
After Jerry Coffin answered I tested the 1st 2 approaches using this program in code:blocks IDE 12.11 using GNU GCC Compiler(Version not stated in the compiler settings).
#include<stdio.h>
int main()
{
int x = 3; //Some arbitrary value
//1st one
scanf("%*[^\n]\n");
scanf("%d", &x);
printf("%d\n", x);
x = 3;
//2nd one
scanf("%*[^\n]%*c");
scanf("%d", &x);
printf("%d", x);
}
I used the following 2 inputs
First Test Input (2 Newlines but no spaces in the middle of garbage input)
abhabdjasxd
23
bbhvdahdbkajdnalkalkd
46
For the first I got the following output by the printf statements
23
46
i.e. both codes worked properly.
Second Test input: (2 Newlines with spaces in the middle of garbage input)
hahasjbas asasadlk
23
manbdjas sadjadja a
46
For the second I got the following output by the printf statements
23
3
Hence I found that the second one won't be taking care of extra garbage input whitespaces. Hence, it isn't foolproof against garbage input.
I decided to try out a 3rd test case (garbage includes newline before and after the non-whitespace character)
``
hahasjbas asasadlk
23
manbdjas sadjadja a
46
The answer was
3
3
i.e. both failed in this test case.
The first two are subtly different: they both read and ignore all the characters up to a new-line. Then the first skips all consecutive white space so after it executes, the next character you read will be non-whitespace.
The second reads and ignores characters until it encounters a new-line then reads (and discards) exactly one more character.
The difference will show up if you have (for example) double-spaced text, like:
line 1
line 2
Let's assume you read to somewhere in the middle of line 1. If you then execute the first one, the next character you read in will be the 'l' on line 2. If you execute the second, the next character you read in will be the new-line between line 1 and line 2.
As for the third, if I were going to do this at all, I'd do something like:
int ch;
while ((ch=getchar()) != EOF && ch != '\n')
;
...and yes, this does work correctly -- && forces a sequence point, so its left operand is evaluated first. Then there's a sequence point. Then, if and only if the left operand evaluated to true, it evaluates its right operand.
As for performance differences: since you're dealing with I/O to start with, there's little reasonable question that all of these will always be I/O bound. Despite its apparent complexity, scanf (and company) are usually code that's been used and carefully optimized over years of use. In this case, the hand-rolled loop may be quite a bit slower (e.g., if the code for getchar doesn't get expanded inline) or it may be about the same speed. The only way it stands any chance of being significantly faster is if the person who wrote your standard library was incompetent.
As far maintainability: IMO, anybody who claims to know C should know the scan set conversion for scanf. This is neither new nor rocket science. Anybody who doesn't know it really isn't a competent C programmer.
The first 2 examples use a feature of scanf that I didn't even know existed, and I'm sure a lot of other people didn't know. Being able to support a feature in the future is important. Even if it was a well known feature, it will be less efficient and harder to read the format string than your 3rd example.
The third example looks fine.
(edit history: I made a mistake saying that ANSI-C did not guarantee left-to-right evaluation of && and proposed a change. However, ANSI-C does guarantee left-to-right evaluation of &&. I'm not sure about K&R C, but I can't find any reference to it and no one uses it anyways...)
Many other solutions have the problem that they cause the program to hang and wait for input when there is nothing left to flush. Waiting for EOF is wrong because you don't get that until the user closes the input completely!
On Linux, the following will do a non-blocking flush:
// flush any data from the internal buffers
fflush (stdin);
// read any data from the kernel buffers
char buffer[100];
while (-1 != recv (0, buffer, 100, MSG_DONTWAIT))
{
}
The Linux man page says that fflush on stdin is non-standard, but "Most other implementations behave the same as Linux."
The MSG_DONTWAIT flag is also non-standard (it causes recv to return immediately if there is no data to be delivered).
You should use getline/getchar:
#include <stdio.h>
int main()
{
int bytes_read;
int nbytes = 100;
char *my_string;
puts ("Please enter a line of text.");
/* These 2 lines are the heart of the program. */
my_string = (char *) malloc (nbytes + 1);
bytes_read = getline (&my_string, &nbytes, stdin);
if (bytes_read == -1)
{
puts ("ERROR!");
}
else
{
puts ("You typed:");
puts (my_string);
}
return 0;
I think if you see carefully at right hand side of this page you will see many questions similar to yours. You can use fflush() on windows.

Resources