LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Small C issue.. "expected expression before.." (https://www.linuxquestions.org/questions/programming-9/small-c-issue-expected-expression-before-693678/)

skuzye 12-29-2008 11:28 AM

Small C issue.. "expected expression before.."
 
Note: The main questions has been solved already but there's good info for novices down there. If you have some spare time, it won't hurt to read further :)

Hello, I'm currently studying C with "C Programming Language Second Ed." and I just can't figure out what's wrong with my code.

I'd appreciate a small hint here.

The error:
Quote:

supercount2.c: In function 'main':
supercount2.c:23: error: expected expression before 'else'
note: I marked the line which contains the else referred.

And the code:
Code:

#include <stdio.h>

main() {
// This program counts spaces (blanks), characters, tabs, newlines and words.

#define IN 1;        // defines if it's in a word
#define OUT 0;        // or not ;)

        long int blanks = 0, chars = 0, tabs = 0, newlines = 0, words = 0;
        int c;
        char state;
       
        while ((c = getchar()) != EOF) {
                ++chars;
                if (c == ' ')
                        ++blanks;
                if (c == '\t')
                        ++tabs;
                if (c == '\n')
                        ++newlines;
                if (c == ' ' || c == '\t' || c == '\n')
                        state = OUT;
                else if (state == OUT) { // error before this line
                        state = IN;
                        ++words;
                }
        }
       
        printf("Blanks: %ld\nCharacters: %ld\nTabs: %ld\nNewlines: %ld\nWords: %ld\n", blanks, chars, tabs, newlines, words);

        return 1;
}

Thanks. Skuzye

Guttorm 12-29-2008 11:36 AM

Code:

#define IN 1;        // defines if it's in a word
#define OUT 0;        // or not ;)

Don't use ; in #defines. Also, the // will be included in the value, so you will get comments in funny places.

Code:

#define IN 1        /* defines if it's in a word */
#define OUT 0        /* or not ;) */


chrism01 12-29-2008 06:07 PM

'else' can only come after a matching 'if', ie

Code:

if (x == 'x' )
{
    something;
}
else
{
    something_else;
}

You're using the single line 'if'

Code:

if( x == 'x')
    something;

no curly parentheses after the 'if' means a single line 'if' block.
Personally I ALWAYS use parentheses to avoid probs like that, also if you go to add a debug line to the (implied) if block, it'll fail...

Its also unusual to have #define other than at the top of the prog, just after the #includes. Its just a directive to the pre-processor to do a simple text substitution everywhere it matches, as per Guttorm's comment.

skuzye 12-29-2008 06:27 PM

Edit: It's interesting because on the book it's written without curly braces and it's supposed to work but it actually doesn't.

Thanks a lot guys... Skuzye

swodniw 12-29-2008 06:46 PM

Quote:

Originally Posted by chrism01 (Post 3390943)
'else' can only come after a matching 'if', ie

Code:

if (x == 'x' )
{
    something;
}
else
{
    something_else;
}

You're using the single line 'if'

Code:

if( x == 'x')
    something;

no curly parentheses after the 'if' means a single line 'if' block.

That I am sorry to say is utter nonsense. Just try looking at any examples in the standard.

skuzye 12-29-2008 08:23 PM

ops.. :P
 
Quote:

Originally Posted by swodniw (Post 3390978)
That I am sorry to say is utter nonsense. Just try looking at any examples in the standard.

You're right, after fixing #define issue I tried to compile without curly braces and it worked flawlessly.

johnsfine 12-30-2008 08:59 AM

Guttorm and swodniw's answers were correct (at least the main part) and maybe enough. But I think Tinkster might still be missing the key point:
Code:

if( x == 'x')
    something;
else
    ...

is OK

Code:

if( x == 'x')
    something;;

is OK (with an extra ; and without an else).

Code:

if( x == 'x')
    something;;
else
    ...

is not OK. With an extra ; the else doesn't work.

If the ; is included when you define OUT and included again when you use OUT then the compiler must parse two ; in a row.

Quote:

Originally Posted by Guttorm (Post 3390561)
Also, the // will be included in the value

Really? I'm not sure about it and I don't have time to test at the moment, but I think I've used // comments on #define instructions many times assuming the // and comment did not become part of the definition. I never had any problems with that.

taylor_venable 12-30-2008 09:30 AM

Quote:

Originally Posted by johnsfine (Post 3391569)
Really? I'm not sure about it and I don't have time to test at the moment, but I think I've used // comments on #define instructions many times assuming the // and comment did not become part of the definition. I never had any problems with that.

With GCC, it depends on what standard you're compiling against. With -std=c89 you will get the // ... included, but with -std=c99 you won't. The default in my version (3.3.5) uses (I believe) -std=gnu89 by default which allows C++ line comments and thus eliminates them without putting them in the definition.

skuzye 12-31-2008 07:46 AM

Just one more question.
 
I was examining again this code and I noted that I stored an integer number in a char type variable and I haven't noted any issues with that. Is it ok? I mean, I can see it's possible but is it a good practice?

I just can't see why to use an integer(4bytes) or even a short integer(2 bytes) if I just need to store 1 or 0 and a char type is 1 byte.

Skuzye

johnsfine 12-31-2008 08:34 AM

Quote:

Originally Posted by skuzye (Post 3392541)
I was examining again this code and I noted that I stored an integer number in a char type variable

Do you mean
Code:

state = OUT;
Quote:

and I haven't noted any issues with that. Is it ok?
It is ok.

Quote:

I mean, I can see it's possible but is it a good practice?
On most architectures you should assume that int is the fastest data type for function local variables and that for an individual (not array) function local variable, the space advantage (if it exists at all) of using something smaller than int is insignificant.

Depending on what else you do with the variable "state", this is likely to be one of the less common cases (for x86 or x86-64) where a char results in faster code than an int.

I personally would tend to use a char for that variable, but I consider that choice pretty arbitrary. Neither char nor int would be considered more or less "good practice" in this case.

Best practice in C++ for that variable would be either:
Rename it so that it is meaningful with values true and false, and then use a bool.
or Define IN and OUT within an enum (much better than #define anyway) and then make "state" that enum type.
(but I forget how much of the above is reasonable in C rather than C++).

Quote:

I just can't see why to use an integer(4bytes) or even a short integer(2 bytes) if I just need to store 1 or 0 and a char type is 1 byte.
Saving storage space should not be considered AT ALL for a scalar local variable. So I don't object to "state" being a char, but I do strongly object to that reason for "state" being char.

swodniw 12-31-2008 09:42 AM

johnsfine has pointed out the why's and why not of using a char/int; yet as you are using C and there are only two possible values have you considered using a bool. bool was introduced to the language with C99 and requires the header stdbool.h
You could change the code to something like
Code:

bool in = false;
/*removed code here*/
else if (in) {
in = !in;
++words;
}


johnsfine 12-31-2008 10:10 AM

Swodniw, I think you have that test backwards and I think
Code:

in = !in;
is pointlessly confusing. I also think the name "in" is not clear enough for a boolean state variable.

Skuzye, I didn't notice before that you failed to initialize "state". That is another bug in your code.

Using bool (assuming that C++ or C99 construct is OK to use) I suggest:
Code:

        bool in_word = false;
        ...
                if (c == ' ' || c == '\t' || c == '\n')
                        in_word = false;
                else if ( ! in_word ) {
                        in_word = true;
                        ++words;
                }


swodniw 12-31-2008 10:17 AM

Quote:

Originally Posted by johnsfine (Post 3392660)
Swodniw, I think you have that test backwards and I think
Code:

in = !in;
is pointlessly confusing. I also think the name "in" is not clear enough for a boolean state variable.

It would seem I do, yet the code was just for demo and it is personal taste if in=!in is confusing. A better name would be whitespace.
Quote:

Skuzye, I didn't notice before that you failed to initialize "state". That is another bug in your code.
quite correct.

skuzye 12-31-2008 10:45 AM

Quote:

Originally Posted by johnsfine
Do you mean
Code:

state = OUT;

Yes.

Quote:

Originally Posted by johnsfine
Saving storage space should not be considered AT ALL for a scalar local variable.

I know it's only a small thing, but can it make any difference in a big project (considering you use similar implementations a lot)?

Quote:

Originally Posted by johnsfine
So I don't object to "state" being a char, but I do strongly object to that reason for "state" being char.

I'm sorry, I didn't understand what you meant :(

Quote:

Originally Posted by johnsfine
Rename it so that it is meaningful with values true and false, and then use a bool.

Quote:

Originally Posted by swodniw
...have you considered using a bool. bool was introduced to the language with C99 and requires the header stdbool.h

I thought about it but as I said I'm learning from C Programming Language and bool was not introduced to me yet :P (I don't see why, it seems so simple).

Skuzye

johnsfine 12-31-2008 11:30 AM

Quote:

Originally Posted by skuzye (Post 3392690)
I know it's only a small thing, but can it make any difference in a big project (considering you use similar implementations a lot)?

No it (the space of the local variable itself) can't make a difference.

The compiler probably would use registers in a way such that there isn't actually any difference in data size. If there were a difference in data size, any difference in code size would likely be bigger than the difference in data size. Unless you are very experienced in both asm and C, you can't predict the difference in code size that results from using char vs. int for a function local variable. More often than not the code for char will be larger (and slightly slower) than the code for int. But it can go either way.

Quote:

I'm sorry, I didn't understand what you meant :(
I meant that this data type decision should be made on the basis of coding style or readability of the code or maintainability of the code or (if it matters) execution speed. The decision should not be made on the basis of data size. When you have a big array (or more complex container) of objects, you should consider data size as a factor in designing those objects. When you have ordinary objects one at a time, you don't consider their size.

Quote:

I thought about it but as I said I'm learning from C Programming Language and bool was not introduced to me yet
How about "enum"? Was that introduced yet? I think enum is the best data type for this in C.

skuzye 12-31-2008 12:21 PM

Lightening fast answer :P

Quote:

...(if it matters) execution speed...
Now talking about coding itself (not restricted by this kind of silly things but with bigger issues), I mean, it won't make any difference at all because nowadays nobody uses a processor that would care about this slight change in code. The question is: even if it's only to make things more correct as possible and not for the sake of speed improvement (but not forgetting about it), should I care about these stuff?
Quote:

When you have a big array (or more complex container) of objects, you should consider data size as a factor in designing those objects. When you have ordinary objects one at a time, you don't consider their size.
That's interesting. I've been reading some stuff and I think a light came to me hahaha...

Let me know if I understood something:

1. Shrinking code would matter because smaller code is stored on faster memories. (link)

Quote:

Your programs get faster when they have stronger locality, because that makes the caching work better. The easiest way to make programs fast is therefore to make them small.
2. Local variables doesn't matter too much if it's large or not because there are not stored with program code in memory. It's stored at stack segment while code itself is stored at text segment. (Hacking - The Art of Exploitation 2nd Edition)

Is this right?

Quote:

How about "enum"? Was that introduced yet? I think enum is the best data type for this in C.
I'm currently reading Chapter 1.6 and enum is presented at 2.3.

Skuzye

johnsfine 12-31-2008 05:00 PM

Quote:

Originally Posted by skuzye (Post 3392763)
1. Shrinking code would matter because smaller code is stored on faster memories.

That is often true, so smaller code often means faster even if the ordinary CPU execution speed of the smaller code isn't faster.

I didn't mean to imply you should routinely take that into account when coding. You shouldn't. But you seemed to want to know what would be better when you think about the possibility that lots of tiny differences might add up to a significant difference. Then the code size for using char local variables vs. int local variables might add up to something that matters. The data size difference won't.

Quote:

2. Local variables doesn't matter too much if it's large or not because there are not stored with program code in memory. It's stored at stack segment while code itself is stored at text segment.
Large local variables (arrays and structures, etc.) are stored on the stack. Small local variables in complicated functions may also be stored on the stack. But small local variables in simple functions are stored in registers.

On the stack, the data storage size difference between a char and an int usually makes less difference than when stored elsewhere in memory. More often than not, it makes no difference. When stored in a register it is near certain that the data storage size makes no difference (the rest of that register won't be used for anythig else anyway).

So even when you care about tiny differences (such as the possible code size difference) which you usually shouldn't care about, you still shouldn't care about the strage space fscalar local variables.

Quote:

I'm currently reading Chapter 1.6 and enum is presented at 2.3.
When you ask about "good practice" (as you did earlier today) you should expect to be told to use features that are further ahead than your lessons have reached so far.

skuzye 01-01-2009 01:08 PM

Thanks a lot!

Quote:

When you ask about "good practice" (as you did earlier today) you should expect to be told to use features that are further ahead than your lessons have reached so far.
No problem at all. It's good because when I get there I know it's important and I'll pay more attention to it :D

Well I guess this is enough for this thread if you don't mind. I can't see how to go further, although if you have any indications of websites or book I'd appreciate.

Skuzye

agemo 01-02-2009 06:07 AM

A couple of suggestions, sorry I didn't post them earlier but they didn't came to mind then:
First, avoid using #define when dealing with constants. Use const typename for that. const gives your compiler a chance to check for type compatibility and it is also useful to avoid errors like the one you've experienced. #define is useful when you want to write portable code, for example:
Code:

#ifdef PLATFORM == WINDOWS
void draw_line(int x1, int y1, int x2, int y2)
{
  //draw a line using DirectX API
}
#elif PLATFORM == LINUX
void draw_line(int x1, int y1, int x2, int y2)
{
  //draw a line using OpenGL API
}
#else
void draw_line(int x1, int y1, int x2, int y2)
{
  //implement some kind of slow, universal, line-drawing function
}

Second, let's say you are given a list of numbers from 0 to 2^32 - 1 (unsigned ints), and you want to see which numbers appear and which don't. If you want to solve this linearly, meaning you make a single pass over the data, you could implement a char array of 2^32 elements, with x[q] == 1 if q is in the list and x[q] == 0 if q isn't. In terms of space that would take 2^32 bytes = 2^22 Kbytes = 2^12 Mbytes = 4GB of RAM!!
Instead, think of what will happen in case you use EVERY bit in your array (and not just the first from every element).
Thus, the 0-th bit of x[0] will store weather 0 is located in the list or not;
the 1-st bit of x[0] will store info. about 1
...
the 7-th bit of x[0] will store info. about 7
Information about number 59412 will be stored on the fourth bit of x[7426]. Using this technique the total size drops 8 times, or sizeof(char), to a respectable value of 512MB of RAM.
In case you were not familiar with this method, I suggest looking up 'bitsets' or 'bit arrays' (C++ has it's own bitset class, but I would stay away from that until I've understood them well).
In case you already knew about bitsets... well sorry to take you time :P Maybe somebody else will benefit from it.

Cheers!

skuzye 01-02-2009 07:52 AM

@agemo

Really interesting. I laughed when you said it would take 4GB of RAM, I can't even imagine such a result in a computer with less RAM than it (which isn't so rare, huh..hehe)

I didn't know about it thank you, you didn't take my time :P

johnsfine 01-02-2009 09:16 AM

Quote:

Originally Posted by agemo (Post 3394378)
First, avoid using #define when dealing with constants.

I agree.

Quote:

Use const typename for that.
My lack of memory regarding C may be a problem here (I've used C++ rather than C for a long time), but I think there are some stupid flaws in the language rules for const typename that make it a much less effective construct than it ought to be.

Certainly in C++ there are such flaws.

I always use enum when the constant I'm defining logically ought to be a const int (I've done that for so long, I've forgotten some of the flaws in const that made me start doing it) . C++ seems to have better support for enum and an enum can do all the things that a const int could have done.

IIRC, const double is even more flawed in C++ language rules than const int and there is no similar work around. I still try hard to avoid needing to use #define, which is even more flawed.

A scalar constant should be something you can define in a header file with the scoping benefits of whatever scope (typically a class definition) you want to give it. C++ doesn't work that way, which is a flaw in the language specification.

#define ignores ordinary scoping rules and its scope is normally the rest of the compilation unit in which it was seen. That makes it even worse than the flawed rules for const typename.

swodniw 01-02-2009 10:01 AM

Quote:

Originally Posted by johnsfine (Post 3394557)
I agree.
My lack of memory regarding C may be a problem here (I've used C++ rather than C for a long time), but I think there are some stupid flaws in the language rules for const typename that make it a much less effective construct than it ought to be.

Certainly in C++ there are such flaws.

Please explain what these "stupid flaws" are.

Quote:

I always use enum when the constant I'm defining logically ought to be a const int (I've done that for so long, I've forgotten some of the flaws in const that made me start doing it) . C++ seems to have better support for enum and an enum can do all the things that a const int could have done.
What are the differences between C and C++ enums besides using the enum keyword?

Quote:

IIRC, const double is even more flawed in C++ language rules than const int and there is no similar work around. I still try hard to avoid needing to use #define, which is even more flawed.
Work around for what flaw?
Quote:

A scalar constant should be something you can define in a header file with the scoping benefits of whatever scope (typically a class definition) you want to give it. C++ doesn't work that way, which is a flaw in the language specification.
Why should it be this way for all scalar types and who says it is a flaw? Constant class members have static linkage, every heard of the one definition rule?

johnsfine 01-02-2009 10:32 AM

Quote:

Originally Posted by swodniw (Post 3394628)
Why should it be this way for all scalar types and who says it is a flaw? Constant class members have static linkage, every heard of the one definition rule?

Yes I've heard of the one definition rule. I just happen to think language design decisions should have been made in the way that lets us write the most effective and maintainable software in that language, not to satisfy abstract absolutes of language purity.

C++ would be a better language (would let us write more effective and more maintainable programs) if constant class members could be defined within the class definition.

swodniw 01-02-2009 10:34 AM

Quote:

Originally Posted by johnsfine (Post 3394670)
C++ would be a better language (would let us write more effective and more maintainable programs) if constant class members could be defined within the class definition.

Some can. So what are these "stupid flaws" you talk about.


All times are GMT -5. The time now is 03:37 PM.