I'm getting undefined behavior in switch/case


C

Chad

The program:

#include <stdio.h>

void hello(void) {
printf("hello \n");
}

void hi(void) {
printf("hi \n");
}

void no(void) {
printf("no\n");
}

int main(int argc, char *argv[]) {
int c;

while(--argc > 0)
while(c = *++argv[0])
switch(c) {
case 'a':
hello();
break;
case 'b':
hi();
break;
default:
no();
break;
}

return 0;
}

And here is what I get.

[email protected]:~/flood> gcc -g -Wall switch.c -o switch
switch.c: In function `main':
switch.c:19: warning: suggest parentheses around assignment used as
truth value
[email protected]:~/flood> ./switch
[email protected]:~/flood> ./switch a
no
no
no
no
no
no
no
[email protected]:~/flood> ./switch b
no
no
no
no
no
no
no
[email protected]:~/flood>

What is my error in logic here?

Chad
 
Ad

Advertisements

M

mark_bluemel

Chad wrote:

Here's a variant on your program which will help you understand what's
going on :-
The program:

#include <stdio.h> [snip]

int main(int argc, char *argv[]) {
int c;

while(--argc > 0)
while(c = *++argv[0])
printf("got [%c]\n",c);
 
L

Lew Pitcher

Chad said:
The program:

#include <stdio.h>

void hello(void) {
printf("hello \n");
}

void hi(void) {
printf("hi \n");
}

void no(void) {
printf("no\n");
}

int main(int argc, char *argv[]) {
int c;

while(--argc > 0)
while(c = *++argv[0])
switch(c) {
case 'a':
hello();
break;
case 'b':
hi();
break;
default:
no();
break;
}

return 0;
} [snip]
What is my error in logic here?

The statement
while(c = *++argv[0])
isn't doing what you think that it is doing

argv[0] is a pointer to a char
++argv[0] modifies this pointer to point to the char after argv[0]
*++argv[0] is the char that is one char after argv[0]

It is worth noting that argv[0] is supposed to be the name of your
program. It is /not/ the first argument you gave to the program.

So, you iterate through the 2nd and subsequent characters of your
program name until you hit the end-of-string terminator. Since none of
those characters match your two explicit case values, they all drop
into the default case, and you get the output you see.
 
K

Kenneth Brody

Chad wrote:
[...]
while(--argc > 0)
while(c = *++argv[0]) [...]
What is my error in logic here?

The second while loop doesn't do what you think it does.
From context, I assume what you want is the first character of
the next argv[] entry. Is that correct? What you are getting
instead is the next character of argv[0].

That is, "++argv[0]" is equivalent to "++(argv[0])" and not the
"(++argv)[0]" that you thought. You could use "**++argv"
instead. (Eliminating the "[0]" makes it clearer that you don't
really mean the program name -- "argv[0]" -- but rather the
current argv entry. At least it does to me.)

Also, to eliminate the compiler warning about "assigment used as
truth value", you can do:

while ( (c = **++argv) != '\0' )

Again, the logic is the same, but it makes your intentions clearer
to both the compiler and human reader. ("Yes, I really meant it
to me an assignment, and not an equality comparison.)

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
B

Boltar

Lew said:
argv[0] is a pointer to a char
++argv[0] modifies this pointer to point to the char after argv[0]

This shouldn't really happen since array indexes should be offsets of
the array pointer , not pointer variables in their own right that can
be modified so in reality doing ++argv[0] should generate an error as
its equivalent to doing ++(argv + 0). I'm curious to know if the above
code is allowed on all compilers.

B2003
 
Ad

Advertisements

B

Ben Bacarisse

Boltar said:
Lew said:
argv[0] is a pointer to a char
++argv[0] modifies this pointer to point to the char after argv[0]

This shouldn't really happen since array indexes should be offsets of
the array pointer , not pointer variables in their own right that can
be modified so in reality doing ++argv[0] should generate an error as
its equivalent to doing ++(argv + 0). I'm curious to know if the above
code is allowed on all compilers.

It must be accepted as it is perfectly valid C. argv[0] is an lvalue
but argv + 0 is not. argv[0] is equivalent to *(argv + 0) and not to
argv + 0.
 
Ad

Advertisements


Top