Array-problems [newbie]

T

Tim Cambrant

Hi, I've been experimenting with C for about a week now and I've read the
tutorial at http://www.geocities.com/tom_torfs/cintro.html, so i feel quite
sure of the syntax and the program flow now. However, I don't seem to have
the right understanding of how arrays really work, since this test-program
of mine doesn't compile right.

-------------

#include <stdio.h>
#include <string.h>

int parse_args(char cmd_arg[]);

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

for (i=1; i < argc; i++) {
arg_check = parse_args(argv);

if (arg_check == 1)
printf("Error: %s is an unknown command.", argv);
}

return 0;
}

int parse_args(char cmd_arg[])
{
switch(cmd_arg) {
case 'test1':
printf("%s\n", cmd_arg);
return 0;
case 'test2':
printf("%s\n", cmd_arg);
return 0;
default:
return 1;
}
}

-------------

When I try to compile this i get these errors:

$ gcc -Wall test.c -o test
test.c: In function `parse_args':
test.c:22: switch quantity not an integer
test.c:23: character constant too long
test.c:26: character constant too long
test.c:24: warning: unreachable code at beginning of switch statement
$

I think it all depends on the fact that I don't know how to format the code
correctly when handling arrays (Where to use "array[]", "array[x]" or
"array"). I think I can recall having problems with the same thing a year
ago when giving C++ a go. What am I doing wrong?

I think you'll understand the programs purpose, so I won't have to explain
it.
 
F

foo bar

int parse_args(char cmd_arg[])
{
switch(cmd_arg) {
case 'test1':
printf("%s\n", cmd_arg);
return 0;
case 'test2':
printf("%s\n", cmd_arg);
return 0;
default:
return 1;
}
}

There are a few errors in your above code.

First, string constants are enclosed with double-qoutes "test1".
Character constants are enclosed with single-qoutes 'c'.

You can't test for strings in switch-statements. The case-expression must be
constant value.
Even though "test1" is a string constant, its value is the address to the
first character in the un-named
character array "test1". Your code would (provided changing 'test1' to
"test1") only do switch on
addresses to those strings, and that isn't what you want.

To compare strings, use the standard strcmp() function, together with
if-else-statements.

Hope it helps.
 
T

Tim Cambrant

foo bar said:
There are a few errors in your above code.

First, string constants are enclosed with double-qoutes "test1".
Character constants are enclosed with single-qoutes 'c'.

You can't test for strings in switch-statements. The case-expression must be
constant value.
Even though "test1" is a string constant, its value is the address to the
first character in the un-named
character array "test1". Your code would (provided changing 'test1' to
"test1") only do switch on
addresses to those strings, and that isn't what you want.

To compare strings, use the standard strcmp() function, together with
if-else-statements.

Hope it helps.


That helps a lot, thank you.

Could I use a struct or something to keep track of all possible command line
arguments, and then use the original switch-statement to check them? It just
doesn't seem very "clean" to use a long if-else-statement. What do most
people do?
 
M

Mark A. Odell

int parse_args(char cmd_arg[])
{
switch(cmd_arg) {
case 'test1':
printf("%s\n", cmd_arg);
return 0;
case 'test2':
printf("%s\n", cmd_arg);
return 0;
default:
return 1;
}
}

There are a few errors in your above code.

First, string constants are enclosed with double-qoutes "test1".
Character constants are enclosed with single-qoutes 'c'.

An aside. Weird as it looks I've seen people encode small words in 32-bit
quantities using the single quotes. E.g. assume an int is 32-bits...

void foo(int input)
{
switch (input)
{
case 'fish'
printf("Input was fish\n");
break;

case 'Mark'
printf("Input was Mark\n");
break;

default: printf("Bad input\n");
}
}
 
T

Tim Hagan

Tim said:
Hi, I've been experimenting with C for about a week now and I've read the
tutorial at http://www.geocities.com/tom_torfs/cintro.html, so i feel quite
sure of the syntax and the program flow now. However, I don't seem to have
the right understanding of how arrays really work, since this test-program
of mine doesn't compile right.

-------------

#include <stdio.h>
#include <string.h>

int parse_args(char cmd_arg[]);

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

for (i=1; i < argc; i++) {
arg_check = parse_args(argv);

if (arg_check == 1)
printf("Error: %s is an unknown command.", argv);


Add \n to the end of the format string. Otherwise you may never see the
message.
}

return 0;
}

int parse_args(char cmd_arg[])
{
switch(cmd_arg) {

switch requires an integer argument. You're trying to give it a string.
case 'test1':

'test' is not a string. It isn't even a character. And it certainly ain't an
integer. (BTW "test" is the proper way to denote a string.)
printf("%s\n", cmd_arg);
return 0;
case 'test2':
printf("%s\n", cmd_arg);
return 0;
default:
return 1;
}
}

A switch won't work in this case. :)

You could try something like the following instead. (There are probably more
efficient ways to do this.)

int parse_args(char cmd_arg[])
{
if (strcmp(cmd_arg, "test1") == 0)
{
printf("%s\n", cmd_arg);
return 0;
}
else if (strcmp(cmd_arg, "test2") == 0)
{
printf("%s\n", cmd_arg);
return 0;
}
else
return 1;
}
-------------

When I try to compile this i get these errors:

$ gcc -Wall test.c -o test
test.c: In function `parse_args':
test.c:22: switch quantity not an integer
test.c:23: character constant too long
test.c:26: character constant too long
test.c:24: warning: unreachable code at beginning of switch statement
$

I think your compiler is trying to tell you something.

You should also reduce the size of your indents from 8 characters (or tab) to
something reasonable like 2 or 4.
I think it all depends on the fact that I don't know how to format the code
correctly when handling arrays (Where to use "array[]", "array[x]" or
"array"). I think I can recall having problems with the same thing a year
ago when giving C++ a go. What am I doing wrong?

I think you'll understand the programs purpose, so I won't have to explain
it.
 
B

Ben Pfaff

Mark A. Odell said:
An aside. Weird as it looks I've seen people encode small words in 32-bit
quantities using the single quotes. E.g. assume an int is 32-bits...

The portability problem with that is that there's no standard way
to map constants that contain more than one character into
integers (C99 6.4.4.1):

The value of an integer character constant containing more
than one character (e.g., 'ab'), or containing a character
or escape sequence that does not map to a single-byte
execution character, is implementation-defined.
 
T

Tim Cambrant

Tim Hagan said:
You could try something like the following instead. (There are probably more
efficient ways to do this.)

int parse_args(char cmd_arg[])
{
if (strcmp(cmd_arg, "test1") == 0)
{
printf("%s\n", cmd_arg);
return 0;
}
else if (strcmp(cmd_arg, "test2") == 0)
{
printf("%s\n", cmd_arg);
return 0;
}
else
return 1;
}
Worked great, thank you.
I think your compiler is trying to tell you something.

Obviously :)
You should also reduce the size of your indents from 8 characters (or tab) to
something reasonable like 2 or 4.

Well, to quote Linus Torvalds on that one...

"Now, some people will claim that having 8-character indentations makes the
code move too far to the right, and makes it hard to read on a 80-character
terminal screen. The answer to that is that if you need more than 3 levels
of indentation, you're screwed anyway, and should fix your program."

I agree with him. I like 8-character tabs because it increses the
readability for me. I suppose that if i ever share my sources to someone who
can't read it, i'll just write a simple converter or something. :)
 
M

Mark A. Odell

The portability problem with that is that there's no standard way
to map constants that contain more than one character into
integers (C99 6.4.4.1):

The value of an integer character constant containing more
than one character (e.g., 'ab'), or containing a character
or escape sequence that does not map to a single-byte
execution character, is implementation-defined.

Oh, I did not mean to encourage this oddity and I certainly did not mean
to imply that it was portable, just that I've seen it.
 
R

Randy Howard

Could I use a struct or something to keep track of all possible command line
arguments, and then use the original switch-statement to check them?

Not sure I follow what you mean by that.
It just doesn't seem very "clean" to use a long if-else-statement.

Perhaps not, but that's C. If you prefer another language, you're
in the wrong place. ;-)
What do most people do?

Use one of those ugly if/else thingies. Seriously, you could do something
like have a lookup table which maps arguments strings to integer values,
then switch() on that. Doesn't seem worth the trouble though for
something as basic as command line arguments.
 
J

Jirka Klaue

Tim said:
"Tim Hagan" <[email protected]> skrev i meddelandet ....

Well, to quote Linus Torvalds on that one...

"Now, some people will claim that having 8-character indentations makes the
code move too far to the right, and makes it hard to read on a 80-character
terminal screen. The answer to that is that if you need more than 3 levels
of indentation, you're screwed anyway, and should fix your program."

I'm curious, how Linus would implement the Floyd-Warshall algorithm.
I agree with him. I like 8-character tabs because it increses the
readability for me. I suppose that if i ever share my sources to someone who
can't read it, i'll just write a simple converter or something. :)

Or something. GNU indent is free. :)

Jirka
 
R

Randy Howard

I agree with him. I like 8-character tabs because it increses the
readability for me. I suppose that if i ever share my sources to someone who
can't read it, i'll just write a simple converter or something. :)

Gnu indent does a fine job already, and it's not that simple to write
one that does more than just modify indenting.
 
T

Tim Cambrant

Randy Howard said:
Not sure I follow what you mean by that.

Just ignore it. I was probably rambling on about something I know nothing
about. :)
Perhaps not, but that's C. If you prefer another language, you're
in the wrong place. ;-)

Well, I think I'll stick to C anyway :)
Use one of those ugly if/else thingies. Seriously, you could do something
like have a lookup table which maps arguments strings to integer values,
then switch() on that. Doesn't seem worth the trouble though for
something as basic as command line arguments.

Nah, I don't feel like bothering. If/else will do fine. I come from a
background of Ruby-scripting you see, and the mentality there is that there
are always at least three ways to do one thing, and you should always use
the best way. Just too bad you can't use Ruby to create executable programs,
because it really is an OOP-masterpiece.

Thank you anyway, I think you helped me understand the uglyness of C :)
 
T

Tim Cambrant

Jirka Klaue said:
I'm curious, how Linus would implement the Floyd-Warshall algorithm.

Haha, well, you'd have to ask him. Perhaps a somewhat cocky statement, but I
usually work in a graphical environment with a high resolution, so I don't
really care about line width. Perhaps I'll change one day when I see the
benefits of 4-space tabs. I'll never do 2 tough. It just gets _messy_.
Or something. GNU indent is free. :)

Perhaps, thank you. I didn't know of that program until now.
 
T

Tim Cambrant

Randy Howard said:
Gnu indent does a fine job already, and it's not that simple to write
one that does more than just modify indenting.

Havn't heard of that program before, but now I do :)

If you wrote a program to modify indenting, why would you want it to do more
than that? Of course, a program to correct indenting would be harder, but
since I already indent my code correctly, I would only have to change the
number of spaces to half. Isn't one of the basic ideas of Unix that you
write a program to do one job, and to do that well?
 
T

Tim Cambrant

Karl Heinz Buchegger said:
In real code, things are often not that simple :)

What do I need to do, more than replacing every series of eight spaces in a
file (or, every '\t') with four spaces? Of course that would mess up files
with strings that contain eight spaces, but that could be avoided further.
Of course it would be easier to use regular expressions, but since C doesn't
support this in the standard libraries (or does it?), you would be stuck
with comparing strings.

Please correct me if I'm wrong.
 
A

Arthur J. O'Dwyer

"Karl Heinz Buchegger" <[email protected]> skrev...

[re: indenting code automagically]
What do I need to do, more than replacing every series of eight spaces
in a file (or, every '\t') with four spaces? Of course that would mess
up files with strings that contain eight spaces, but that could be
avoided further. Of course it would be easier to use regular
expressions, but since C doesn't support this in the standard libraries
(or does it?), you would be stuck with comparing strings.

Please correct me if I'm wrong.

My coding style often looks like this:

if (x) {
if (y)
z;
w;
}
else
aa;

Even GNU indent seems to have problems with this style
(four spaces inside braces, two spaces without braces).
At least, *I* never figured out how to make it do what
I wanted.
The nice thing about 'indent' is that it will actually
parse the code for you. It can handle blocks of code
that look like this going in:

if(x){if(y)z;w;}else aa;

and print them out properly indented.
What you're describing is probably what's commonly known
as a 'detab'/'entab' utility. First, 'entab' your code
using a tabstop of 8, and then 'detab' it with a tabstop
of 4. That will shrink your indents appropriately.
IME, most 'detab'/'entab' utilities have options to only
affect whitespace at the beginnings of lines, so you don't
have to worry about your string literals getting messed up.
Clever tabbers might even recognize certain types of literals
or comment text.

And no, the C library doesn't support regexes. But
they're overkill for tabbing. It's an ideal problem for
the while ((c=getchar())!=EOF) ... loop that you've been
hearing so much about. :)

HTH,
-Arthur
 
R

Randy Howard

Havn't heard of that program before, but now I do :)

If you wrote a program to modify indenting, why would you want it to do more
than that?

Because once you've written code smart enough to parse C source to look at
indenting, you might as well handle a lot of other things, like brace
style, blank lines before after various declarations, comment placement,
you name it. A look at the man page for indent will demonstrate that the
name is probably less than descriptive. "reformat" might be a better
term.
Of course, a program to correct indenting would be harder, but
since I already indent my code correctly,

Sadly, not everyone can agree on "correctly" in this context. The nice
thing about a tool like indent is that you don't have to agree.
Isn't one of the basic ideas of Unix that you
write a program to do one job, and to do that well?

In general, the toolbox approach is common, yes. In this case, I think
you'll find that the degree of "one job" varies. Otherwise, why not
just have 38 different versions of the 'ls' command, instead of a very
long list of command line options?
 
R

Randy Howard

Of course, but for me, the newbie/beginner, I would be satisfied with a
simplistic space-replacer. Maybe a bit foolish, since it would be a good
place to start programming seriously,

That's a very good point. I think this is probably as good a project as
any to learn the vagaries of file I/O. It's certainly better than the
typical homework problem, such as "Read this data file and calculate an
electric bill from it"... bleh.
but where I am now, chances are big
that I'd just mess up my original program to a point beyond useability.

Well, that's an easy problem to solve, just make backup copies. ;-)
Odds are that any program you use to learn on will have bugs before
you get it finished. That's the nature of learning to program. Despite
what people might have you believe, no programmer just woke up one day,
bought a computer, and then proceeded to write bug-free programmers
without going through what used to be known as "the larval stage".
 
T

The Real OS/2 Guy

Tim said:
Hi, I've been experimenting with C for about a week now and I've read the
tutorial at http://www.geocities.com/tom_torfs/cintro.html, so i feel quite
sure of the syntax and the program flow now. However, I don't seem to have
the right understanding of how arrays really work, since this test-program
of mine doesn't compile right.

-------------

#include <stdio.h>
#include <string.h>

int parse_args(char cmd_arg[]);

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

for (i=1; i < argc; i++) {
arg_check = parse_args(argv);

if (arg_check == 1)
printf("Error: %s is an unknown command.", argv);


Add \n to the end of the format string. Otherwise you may never see the
message.
}

return 0;
}

int parse_args(char cmd_arg[])
{
switch(cmd_arg) {

switch requires an integer argument. You're trying to give it a string.
case 'test1':

'test' is not a string. It isn't even a character. And it certainly ain't an
integer. (BTW "test" is the proper way to denote a string.)
printf("%s\n", cmd_arg);
return 0;
case 'test2':
printf("%s\n", cmd_arg);
return 0;
default:
return 1;
}
}

A switch won't work in this case. :)

You could try something like the following instead. (There are probably more
efficient ways to do this.)

int parse_args(char cmd_arg[])
{
if (strcmp(cmd_arg, "test1") == 0)
{
printf("%s\n", cmd_arg);
return 0;
}
else if (strcmp(cmd_arg, "test2") == 0)


The else is superflous here as when the if is true the codeflow ends
with the return statement. So only the case that if fails is over to
handle.
{
printf("%s\n", cmd_arg);
return 0;
}
else

Another superflous else
return 1;
}

Do both, shortening the code and make it more flexible:

/* list of commands:
command to check in input, convert to token to have a value to
switch
when we have to handle each cmd differently */
struct cmds {
char *cmd; /* the cmd as pointer to string to use only memory as
needed for a string*/
int token; /* converted to int; should be a preprocessor token
to be self documented */
maybe more values assigned to that specific cmd, e.g. parameters, a
fuction name
that handles the cmd or something else needed to work with that
CMD....
} cmds = {
{ "test1", 1}, /* initialiser list */
{ "test2", 2},
/* insert more cmd's when needed; no code change needed */
{ NULL, 0 } /* no more cmds known */
};

int parse_args(char cmd_arg[]);

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

for (i=1; i < argc; i++) {
/* is argument a known cmd? */
arg_check = parse_args(argv);
if (arg_check == 0)
/* no, it is */
printf("Error: %s is an unknown command.",
argv);
}
return 0;
}

/* check if given string is a cmd and return either
- 0 if cmd is unknown or
- int == cmd as token to have it easy to handle it after it is
identified */
int parse_args(char cmd_arg[])
{
struct cmds *pcmds = cmds;
/* check against list of cmds */
for (; *pcmds; pcmds++)
if (!strcmp(cmds, cmdarg->cmd))
return cmd->token; /* cmd found, return its token */
return 0; /* cmd unknown, return error */
}
 
T

Tim Cambrant

Randy Howard said:
Well, that's an easy problem to solve, just make backup copies. ;-)
Odds are that any program you use to learn on will have bugs before
you get it finished. That's the nature of learning to program. Despite
what people might have you believe, no programmer just woke up one day,
bought a computer, and then proceeded to write bug-free programmers
without going through what used to be known as "the larval stage".

That's of course true. I'm proud of being a novice, and I'm sure I'm less of
a novice now than I was a year ago. (Yes, a year ago. I havn't exactly been
devoted to programming as of yet.)

I'm thinking about writing a c-code parser of some sort. At least I've been
thinking about how to accomplish that for about a day now, and it seems
possible to accomplish, as well as a good task.

Thanks for you help and support :)
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top