PDA

hoangluong
Jan 29, 2009, 04:13 AM
Hi,

I've written a tiny program to convert between Celsius and Fahrenheit and it has run well with results I expected. Then, I decided to revise it a bit and the problem has arisen which I don't know where from. The problem came when I added the code in bold (see the program below).

Could you please point out where the problem is from? Here's the code which gave wrong stuffs:

#include<stdio.h>
#include<ctype.h>

int main(void)
{
char unit = 0;
float temperature = 0.0f;
float Celcius = 0.0f;
float Fahrenheit = 0.0f;

printf("You wanna convert to Celcius or Fahrenheit? C for Celcius, F for Fahrenheit: ");
scanf("%c", &unit);
if(!(unit == 'c') || !(unit == 'C') || !(unit == 'f') || !(unit == 'F'))
printf("\nYou've entered the wrong thing! You didn't read the onscreen instructions, did you?");

else

printf("\nNow enter the temperature you want converted to your chosen unit: ");
scanf("%f", &temperature);

Celcius = (temperature - 32.0f)*(5.0f/9.0f);
Fahrenheit = 1.8f*temperature + 32.0f;

switch (toupper(unit)) {
case 'C':
printf("\nIt's equivalent to %0.3f Celsius", Celcius);
break;
case 'F':
printf("\nIt's equivalent to %0.3f Fahrenheit", Fahrenheit);
break;

}

return 0;
}

What I can't figure out is why it keeps giving the things I highlighted in bold, even though I've entered 'c' or 'C', etc... It just gets stuck there.

Your help is much appreciated!!! I'm trying to teach myself C as the very first language. I don't have programming experience or I've never had any formal computer classes before.

Thanks a lot....

MacRohde
Jan 29, 2009, 04:28 AM
In your if statement you use OR (||) which means that if just one of the four options are true it will be excetued. If you enter 'c' then it is not 'f' or 'F' or 'C' so the if will be true.

You should use && instead. Requiring that it shall not be any of the four options.

hoangluong
Jan 29, 2009, 04:52 AM
In your if statement you use OR (||) which means that if just one of the four options are true it will be excetued. If you enter 'c' then it is not 'f' or 'F' or 'C' so the if will be true.

You should use && instead. Requiring that it shall not be any of the four options.

Thanks so much! It now works properly. Every time I run into this sort of errors and get it corrected owning to help like yours, it just helps me memorize the rules a lot faster... Thanks...

hoangluong
Jan 30, 2009, 01:44 PM
Hi!

Why is it that it runs perfectly well in Terminal if and only if I exclude "int" before main() in a C program, whereas in Xcode I can either exclude or include "int" before main()?

I'm using 2 books: one by Ivor Horton ("Beginning C") who always advocates int main(void), which works well within Xcode, and the other by Kernighan & Ritchie ("The C Programming Language").

I ran the same program using Xcode and then Terminal. In Xcode, it's fine but in Terminal it fails to compile until I delete "int" before main(). In Xcode, if I don't have "int" before main() it gives a warning that int before main() is assumed to be default.

Thanks a lot!

eddietr
Jan 30, 2009, 03:12 PM
In Xcode, it's fine but in Terminal it fails to compile until I delete "int" before main().

What error are you getting exactly?

hoangluong
Jan 30, 2009, 03:46 PM
What error are you getting exactly?

Sorry. It works properly now. I restarted Terminal and it no longer gives warning about "int" or sth.

hoangluong
Jan 31, 2009, 12:27 AM
Below is a program from "Beginning C" by Ivor Horton. It works in Xcode without problems, but when I compile it in Terminal it keeps giving error warnings.

The program:

/* Program 4.9 Sums of integers step-by-step */
#include <stdio.h>

int main(void)
{
long sum = 0L; /* Stores the sum of integers */
int count = 0; /* Number of sums to be calculated */

/* Prompt for, and read the input count */
printf("\nEnter the number of integers you want to sum: ");
scanf(" %d", &count);

for(int i = 1 ; i <= count ; i++ )
{
sum = 0L; /* Initialize sum for the inner loop */

/* Calculate sum of integers from 1 to i */
for(int j = 1 ; j <= i ; j++ )
sum += j;

printf("\n%d\t%ld", i, sum); /* Output sum of 1 to i */
}
return 0;
}

The Terminal's warning:
hoang-luong-luongs-macbook-pro:~ hoangluongluong\$ cd IvorHorton
hoang-luong-luongs-macbook-pro:IvorHorton hoangluongluong\$ ls
p131 p132a.c prog3_3 prog4_2.c prog4_9.c
p131.c p141 prog3_3.c prog4_6
p132a p141.c prog4_2 prog4_6.c
hoang-luong-luongs-macbook-pro:IvorHorton hoangluongluong\$ cc -o prog4_9 prog4_9.c
prog4_9.c: In function ‘main’:
prog4_9.c:13: error: ‘for’ loop initial declaration used outside C99 mode
prog4_9.c:18: error: ‘for’ loop initial declaration used outside C99 mode
hoang-luong-luongs-macbook-pro:IvorHorton hoangluongluong\$

lee1210
Jan 31, 2009, 12:32 AM
In C, generally you have to declare all variables first in a new scope. You cannot declare them later. This goes for a variable you intend to use as a loop control. The { after the for starts a scope you can define new variables in, but in the for itself, you should use a variable you've already declared.

I'm not a C99 expert, but apparently the warning indicates that declaring in the for is supported in C99.

-Lee

hoangluong
Jan 31, 2009, 12:47 AM
In C, generally you have to declare all variables first in a new scope. You cannot declare them later. This goes for a variable you intend to use as a loop control. The { after the for starts a scope you can define new variables in, but in the for itself, you should use a variable you've already declared.

I'm not a C99 expert, but apparently the warning indicates that declaring in the for is supported in C99.

-Lee

Thanks a lot! I tried declaring variables i & j outside of the for loop and it works properly.

eddietr
Jan 31, 2009, 12:50 AM
Yes, C99 allows you to make declarations anywhere in a block.

So, hoangluong, just a small note on terminology, it's not the terminal that is giving you this error, it's the compiler (which in this case is gcc).

C has evolved a bit over the years, and there are multiple accepted standards for C. By default, gcc uses the Gnu89 standard or "flavor" of C. And in that standard, all declarations (such as "int i") must come before any other statements in a block. Which is why your for loop won't compile.

XCode uses gcc also, but by default it sets gcc to use the C99 standard instead, which does allow declarations like "int i" anywhere in the block (such as in your for statement).

You can do this yourself from the terminal also. Just use:

cc -std=c99 -o prog4_9 prog4_9.c

That will tell gcc to use the C99 standard instead of its default. Then you can keep the declarations in the for loop as you had them.

Hope that helps.

hoangluong
Jan 31, 2009, 06:18 AM
Yes, C99 allows you to make declarations anywhere in a block.

So, hoangluong, just a small note on terminology, it's not the terminal that is giving you this error, it's the compiler (which in this case is gcc).

C has evolved a bit over the years, and there are multiple accepted standards for C. By default, gcc uses the Gnu89 standard or "flavor" of C. And in that standard, all declarations (such as "int i") must come before any other statements in a block. Which is why your for loop won't compile.

XCode uses gcc also, but by default it sets gcc to use the C99 standard instead, which does allow declarations like "int i" anywhere in the block (such as in your for statement).

You can do this yourself from the terminal also. Just use:

cc -std=c99 -o prog4_9 prog4_9.c

That will tell gcc to use the C99 standard instead of its default. Then you can keep the declarations in the for loop as you had them.

Hope that helps.

Eddietr, thanks so much for your help!

hoangluong
Feb 2, 2009, 08:28 PM
After writing some simple C programs using TextWrangler and compiling and running them in Terminal, I now have thought of running the programs from within TextWrangler, i.e. writing C programs and clicking on "#!" in Textwrangler. I have followed exactly the instructions on how to run a C program from within TextWrangler, available from the link below:

http://iel.ucdavis.edu/projects/chide/textwrangler/

However, when it comes to clicking "Run in Terminal" that's available on "#!" menu of TextWrangler, I always get this warning:

"This operation couldn't be completed, because an error occured.
The unix tool referenced in the 'shebang' line cannot be found (application error code: 13305)"

This warning always pops up despite me having typed in the shebang line "#!/bin/ch.

I know this is not quite an important issue for a C newbie like me just beginning to learn C, in the sense that I still can always run a C program directly in Terminal. But it is just out of my own curiosity.

Can anyone help me on this?

Thanks a lot!

eddietr
Feb 2, 2009, 09:02 PM
Did you install ch? If so, did you note where?

hoangluong
Feb 3, 2009, 12:55 AM
Hi, I now have been able to run a C program from within TextWrangler. It just launched the Terminal window when I clicked "Run in Terminal" on the "#!" menu. No sooner did I get around a small problem than I ran into another! Using the same program that I ran successfully within Terminal, I tried to run it from within TextWrangler. It launched a Terminal window that's full of errors. The output looks like this:

Last login: Tue Feb 3 19:41:03 on ttys001
hoang-luong-luongs-macbook-pro:~ hoangluongluong\$ /var/folders/6+/6+CTfdSQGLmszIilQCvdAE+++TI/Cleanup\ At\ Startup/prog4_9-255343273.986.c.command ; exit;
ERROR: maybe missing ';'
ERROR: with unnecessary identifier 'i' in casting operator
ERROR: incompatible types for casting operation, casting void to int
ERROR: missing ';' in for-loop
ERROR: syntax error before or at line 13 in file /Users/hoangluongluong/BeginC/prog4_9.c
==>: for(int i = 1; i <= count; i++)
BUG: for(int i = 1; i <=<== ???
ERROR: variable 'i' not defined
ERROR: syntax error before or at line 13 in file /Users/hoangluongluong/BeginC/prog4_9.c
==>: for(int i = 1; i <= count; i++)
BUG: for(int i = 1; i <= count; i<== ???
ERROR: maybe missing ';'
ERROR: with unnecessary identifier 'j' in casting operator
ERROR: incompatible types for casting operation, casting void to int
ERROR: missing ';' in for-loop
ERROR: syntax error before or at line 16 in file /Users/hoangluongluong/BeginC/prog4_9.c
==>: for (int j = 1; j <= i; j++)
BUG: for (int j = 1; j <=<== ???
ERROR: variable 'j' not defined
ERROR: syntax error before or at line 16 in file /Users/hoangluongluong/BeginC/prog4_9.c
==>: for (int j = 1; j <= i; j++)
BUG: for (int j = 1; j <= i; j<== ???
ERROR: argument 2 of the function is undefined or not a valid expression
ERROR: syntax error before or at line 18 in file /Users/hoangluongluong/BeginC/prog4_9.c
==>: printf("// %d\t%ld\n", i, sum);
BUG: printf("// %d\t%ld\n", i<== ???
ERROR: cannot execute command '/Users/hoangluongluong/BeginC/prog4_9.c'
logout

[Process completed]

And the program that I wrote is exactly like this (I've included the shebang line according to the instructions for running C programs from within TextWrangler):

#!/bin/ch
/* Program 4.9 */
#include<stdio.h>

int main(void)
{
long sum = 0l;
int count = 0;

printf("\nEnter the number of integers you want to sum: ");
scanf("%d", &count);

for(int i = 1; i <= count; i++)
{
sum = 0L;
for (int j = 1; j <= i; j++)
sum += j;
printf("// %d\t%ld\n", i, sum);
}

return 0;
}

The program worked properly when I compiled it in Terminal, Macvim or Xcode, but it gives errors here. I don't know what's wrong with it, but I guessed that it might be because of the C99 error, i.e. I included "int" inside the for loop (to my very limited knowledge). In Terminal, as one of your said, I simply added -std=c99 and then it was all fine. In TextWrangler, it's perhaps not possible to do like that.

Does anyone have any idea of this issue? Thanks a lot!

eddietr
Feb 3, 2009, 01:47 PM
So there is a difference between using ch and using gcc. They are two different things.

gcc is a compiler. And XCode uses gcc just the same way as you would yourself by typing 'cc' or 'gcc' in the Terminal. So that's why the results from those two are the same.

And the "-std=c99" flag is a flag to gcc. So only gcc would understand that.

ch, on the other hand, is a C interpreter (not compiler). I have no experience using such a thing, but it may be that 'ch' also has flags that you can use to specify c99 syntax or whatever other things you need. You would have to look at the docs.

but the important thing is to understand that you aren't using gcc this way.

gnasher729
Feb 3, 2009, 04:41 PM
hoangluongluong\$ cc -o prog4_9 prog4_9.c
prog4_9.c: In function ‘main’:
prog4_9.c:13: error: ‘for’ loop initial declaration used outside C99 mode
prog4_9.c:18: error: ‘for’ loop initial declaration used outside C99 mode
hoang-luong-luongs-macbook-pro:IvorHorton hoangluongluong\$

Here's what happens: The gcc compiler can be run with a large list of compiler options that make it compatible with different versions of the C language. Depending on the options, it compiles C89, C90, C99, with or without gcc extensions. When XCode starts the compiler, it will use it in C99 mode (that is the latest version of the C language) unless you change your build settings. If you start the compiler from the command line without any options, it compiles a different, older version of the language.

A loop like "for (int i = 0; i < 10; ++i) { }" uses a feature that is new in C99: Declaring a variable within the parentheses of the for loop. That's exactly the error message that you got: You used an initial declaration (int i = 0; ... ) which is only legal in C99. Declare your loop variables outside the loop, or find the compiler options that are needed for C99.

hoangluong
Feb 7, 2009, 02:11 AM
Hi, I'm trying to use the function strcpy() instead of the while loop that I used for this kind of exercise. It doesn't work. I guess where this function is used in the program is a source of errors, but I don't know how to fix it. Could you please help? Thanks a lot.

/* Program 6.4 */
#include<stdio.h>
#include<string.h>

int main(void)
{
char str[][40] = {"To be or not to be",
", that is the question" };
int count[] = {0,0};

for(int i = 0; i < 2; i++)
while(str[i][count[i]])
count[i]++;
if(sizeof str[0] <= sizeof str[1])
printf("\nYou can't put a quart into a pint pot.\n");
else
{
count[1] = 0;
strcpy(str[0], str[1]);
printf("\n%s\n", str[0]);
}
return 0;
}

subsonix
Feb 7, 2009, 02:30 AM
strcpy() expects pointers as arguments. So strcpy(str[0], str[1]);

should be:

strcpy(&str[0], &str[1]);

hoangluong
Feb 7, 2009, 02:41 AM
strcpy() expects pointers as arguments. So strcpy(str[0], str[1]);

should be:

strcpy(&str[0], &str[1]);

Still, it sends warning errors...

hoang-luong-luongs-macbook-pro:BeginC hoangluongluong\$ gcc -std=c99 -o p212 p212.c
p212.c: In function ‘main’:
p212.c:19: warning: passing argument 1 of ‘strcpy’ from incompatible pointer type
p212.c:19: warning: passing argument 2 of ‘strcpy’ from incompatible pointer type
hoang-luong-luongs-macbook-pro:BeginC hoangluongluong\$

subsonix
Feb 7, 2009, 02:44 AM
Still, it sends warning errors...

hoang-luong-luongs-macbook-pro:BeginC hoangluongluong\$ gcc -std=c99 -o p212 p212.c
p212.c: In function ‘main’:
p212.c:19: warning: passing argument 1 of ‘strcpy’ from incompatible pointer type
p212.c:19: warning: passing argument 2 of ‘strcpy’ from incompatible pointer type
hoang-luong-luongs-macbook-pro:BeginC hoangluongluong\$

Ok then I don´t know. I tried this, it worked.

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

int main(int argc, char *argv[])
{
char str[10];
str[1] = 'a';
str[0] = 0;

strcpy(&str[0], &str[1]);
printf("\n%c\n", str[0]);

return 0;
}

gnasher729
Feb 7, 2009, 05:04 AM
Hi, I'm trying to use the function strcpy() instead of the while loop that I used for this kind of exercise. It doesn't work. I guess where this function is used in the program is a source of errors, but I don't know how to fix it. Could you please help? Thanks a lot.

/* Program 6.4 */
#include<stdio.h>
#include<string.h>

int main(void)
{
char str[][40] = {"To be or not to be",
", that is the question" };
int count[] = {0,0};

for(int i = 0; i < 2; i++)
while(str[i][count[i]])
count[i]++;
if(sizeof str[0] <= sizeof str[1])
printf("\nYou can't put a quart into a pint pot.\n");
else
{
count[1] = 0;
strcpy(str[0], str[1]);
printf("\n%s\n", str[0]);
}
return 0;
}

This code works perfectly fine in XCode. It compiles without any warnings, and it runs fine. What might come unexpected to you is the fact that it prints "You can't put a quart into a pint pot.", but that is because sizeof str [0] is forty, and so is sizeof str [1]. Without that if statement, it prints the second string just fine. str is an array with two elements, and each element is an array of forty chars, so each of the two array elements has size 40.

One thing you should do: Instead of saying "it doesn't work", say what you expected to happen, and what actually happened.

gnasher729
Feb 7, 2009, 05:08 AM
strcpy() expects pointers as arguments. So strcpy(str[0], str[1]);

should be:

strcpy(&str[0], &str[1]);

You are wrong. str [0] is an array of 40 chars. When an array is passed as a parameter to a function, it is automatically converted to a pointer to the first array element, so what is actually passed to the function is a char* pointing to the first character of the first string. The same happens with str [1].

But if you pass &str [0], then you pass a pointer to an array of forty characters. A pointer to an array of forty characters is not the same as a pointer to char, so all you achieved is making the compiler create a warning, with no guarantee that it will work anymore.

hoangluong
Feb 7, 2009, 06:15 AM
This code works perfectly fine in XCode. It compiles without any warnings, and it runs fine. What might come unexpected to you is the fact that it prints "You can't put a quart into a pint pot.", but that is because sizeof str [0] is forty, and so is sizeof str [1]. Without that if statement, it prints the second string just fine. str is an array with two elements, and each element is an array of forty chars, so each of the two array elements has size 40.

One thing you should do: Instead of saying "it doesn't work", say what you expected to happen, and what actually happened.

Hi gnasher729, thanks a lot for your help! Excellent, it all is clear to me now.

subsonix
Feb 7, 2009, 06:34 AM
But if you pass &str [0], then you pass a pointer to an array of forty characters. A pointer to an array of forty characters is not the same as a pointer to char, so all you achieved is making the compiler create a warning, with no guarantee that it will work anymore.

Ok, I did not get any warnings though. I compiled it using gcc in terminal

gnasher729
Feb 7, 2009, 08:10 AM
Ok, I did not get any warnings though. I compiled it using gcc in terminal

The gcc compiler has lots of options to produce warnings. When you compile with XCode, lt will turn on a few of these by default, and they are usually useful. You can manually turn on more; you should decide which ones are useful and which ones are not and turn all the useful ones on.