Bad style notwithstanding, is it legal C to have a for loop with braces inside the parens? Like this:
char *a = "a ";
char *b = "b ";
for ( { int aComesFirst = 1;
char *first = a;
char *second = b;
};
aComesFirst >= 0;
{ aComesFirst--;
swap(first, second);
} )
{
printf("%s%s\n", first, second);
}
If something along those lines is possible, am I supposed to put a semicolon after the first close braces, or would that add an empty statement?
I do realize that it is stylistically better to move the char* declarations outside the for loop and the swap to the end of the inside of the loop. But style is not the point of this question, I just want to know if putting braces inside the parens is possible.
I've answered this before… this can easily be made legal in C or C++ by adding a local struct type. It's generally poor style, though.
char *a = "a ";
char *b = "b ";
for ( struct loopy {
int aComesFirst;
char *first;
char *second;
} l = { 1, a, b }; /* define, initialize structure object */
l.aComesFirst >= 0; /* loop condition */
l.aComesFirst--, /* loop advance */
swap(l.first, l.second)
)
{
printf("%s%s\n", l.first, l.second);
}
No, it's not legal, but you can use commas to get half way there:
for (int a = 1, b = 2; a < 10; ++a, ++b)
You can't declare multiple variables of different types, and you can't use control structures in the last bit, but it's good enough most of the time.
If you didn't know, the comma used there is not some special syntax that can only be used in for loops, it's a general operator that can be used anywhere to evaluate the left operand, followed by the right operand, and return the result of the right expression, i.e. a, b == b, and a, b, c == c and so on.
No, it is not legal. If it was legal the code wouldn't work anyway because c has block level scope, so you wouldn't have access to an of the variables defined in the braces.
That's not legal but this is:
for(i = 0, j = 10; i < 10; i++, j--)
{
// ..
}
See: the comma operator
Are you using the gcc with Statement Expressions? http://tigcc.ticalc.org/doc/gnuexts.html#SEC63
Maybe that will make that type of code work. except it's (int i = { stmts; }; { stmts; bool}; { ... })
The Standard says (6.8.5.3/1)
for ( clause-1 ; expr-2 ; expr-3 ) statement
I'm pretty sure neither expr-2 or expr-3 can be replaced by something not an expression (a block is not an expression), and I'm pretty sure clause-1 also cannot be replaced by a statement.
Related
Consider this simple program:
fails.c:
#include <stdio.h>
int main(){
int i = 10;
if (i == 10)
int j = 11;
return 0;
}
That fails to compile (gcc fails.c), giving this error:
fails.c: In function ‘main’:
fails.c:7:3: error: expected expression before ‘int’
int j = 11;
^
But this one goes through just fine:
#include <stdio.h>
int main(){
int i = 10;
if (i == 10){
int j = 11;
}
return 0;
}
I figured that the work around, is to put those {} in. But I wish to know why this is required.
Why does it behave this way, when something like printf is acceptable?
#include <stdio.h>
int main(){
int i = 10;
if (i == 10)
printf("some text\n");
return 0;
}
This is because if must be followed by a statement:
C99/6.8.4
if ( expression ) statement
However, a declaration is not a statement:
C99/6.8
statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
When put inside a {}, it is a compound-statement, thus ok.
There is a difference between declaration and statement.
int j = 11;
is a declaration. if statement shall be followed by a statement. Putting {} after if statement results in a compound statement. A compound statement can have no other statement in it or can have a declaration.
It seems you compile your ANSI C code with C89 standard. And, unlike his successor C99, it requires all variables to be declared at the beginning of the scope. So, having int j = 11; somewhere in-between other statements just contradicts that C89 rule. If you open a new scope just before that int j = 11;, it's back to OK.
Actual reason of such C89 limitation should be an attempt to simplify memory management for stack-allocable variables. For instance, compare it with Pascal language that requires all variables to be declared in the special var section before the code (so, it's even more strict that C89).
I'm new to programming, I'm taking this online programming course CS50. So I had an assignment to write a program in C, where user inputs some words (no matter how much space there is before or after words) and we have to print first initials of each word. So I made this program:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
int n;
int i;
string name = get_string();
if(name != NULL)
{
if (name[0] != ' ')
{
printf("%c", toupper(name[0]));
}
for(i = 0, n = strlen(name); i < n; i++)
{
if(name[i] ==' ' && isalpha(name[i+1]))
{
printf("%c", toupper(name[i+1]));
}
}printf("\n");
}
}
But it was correctly done only after I declared variables int n; int i;
Before that, I could not even compile program. Why? At first I declared int i
in for loop, but program didn`t even compiled. And just out of luck I tried to declare outside loop and its correct. I dont understand this point. Can someone explain? :)
All variables and functions must be declared before they may be used. The variable i must be declared before it can be used as an index in the for loop.
Under the 1989/1990 standard and earlier K&R language versions, all declarations had to come before any executable statements in a block:
void foo( void )
{
/**
* The variable i is used to control a for loop later on in the function,
* but it must be declared before any executable statements.
*/
int i;
/**
* Some amount of code here
*/
for( i = 0; i < some_value; i++ ) // K&R and C90 do not allow declarations within the loop control expression
{
/**
* The variable j is used only within the body of the for loop.
* Like i, it must be declared before any executable statements
* within the loop body.
*/
int j;
/**
* Some amount of code here
*/
j = some_result();
/**
* More code here
*/
printf( "j = %d\n", j );
}
}
As of the 1999 standard, declarations may be mixed with other statements, and they may appear as part of the initial expression of a for loop:
void foo( void )
{
/**
* Some amount of code here
*/
for ( int i = 0; i < some_value; i++ ) // C99 and later allow variable declarations within loop control expression
{
/**
* Some code here
*/
int j = some_result(); // declare j when you need it
/**
* More code here
*/
printf( "j = %d\n", j );
}
}
The chief difference between the two snippets above is that in the first case, i is visible over the body of the entire function, whereas in the second snippet, it's only visible within the body of the for loop. If you need i to be visible to any code following the for loop, then you need to declare it outside the loop control expression:
int i;
for ( i = 0; i < some_value; i++ )
{
...
}
...
do_something_with( i );
Again, i must be declared before it can be used in the loop control expression; it's just in the second case, that declaration is part of the loop control expression.
EDIT
I don't know what development environment or compiler you are using. You might want to see if you can specify which version of the language you want to compile against (for example, in gcc, you'd specify -ansi or -std=c90 for the 1989/1990 version and -std=c99 for the 1999 version).
First of all - welcome to C language! I think C is a great language to start with.
Variables declaration - in C, we are allowed to declare on a local variable only at the beginning of a scope - at the very beginning of a function, loop, if statement, etc.
For example:
We can't run this:
for(int i = 0; i<4: ++i) { printf("%d",i); }
The declaration is in the for statement - not at the beginning of the scope. In C++, this code will work.
However, we can do the following:
int foo()
{
int i;
for(i=0;i<4; i++) { ...}
}
Remark: local variables and parameters passed are allocated on stack. When we declare on a local variable we push the variable into the stack and we get to the end of the scope - the variable pops out.
I've been coming across this sort of loops, they work as expected but I would love to understand how C compilers see these loops.for(;i<10;i++){}
for(;a;a= a->next){}
for (a; b; c) d; is equivalent to the following:
{
a;
while (b)
{
d;
c;
}
}
So omitting the first part just omits a, i.e. the initialization statement. So the compiler sees it as equivalent to the following:
while (b)
{
d;
c;
}
In your for loop there are three phases that can be observed as:
for(a;b;c) d;
A: Initial declarations
This is assignments or declarations that are preformed at the beginning of the loop.
B: Loop stipulation
This is the stipulation that must be true to continue iteration.
C: Iteration declaration
This is declarations or assignments that will take place after each loop iteration.
D: Loop body
This is the body of the loop that is executed after the A and B but before C.
The order can be observed as:
A();
while(B) {
D();
C();
}
The first part of the for statement is the initialization statement. It simply initializes one of the loop variables. It is normally omitted when its use would be duplicative, e.g.:
int i = 0;
...
for (; i < x; i++) { ... }
As you can see in that example, inclusion of i = 0 would simply repeat the original initialization. You also commonly see the omission related to pointers, for the same reason, i.e.
char buf[] = "a quick brown fox jumped over the lazy dog";
char *p = buf;
...
for (; *p; p++) { ... }
Here again, p = buf would be duplicative.
This question already has answers here:
C function syntax, parameter types declared after parameter list
(7 answers)
Closed 2 years ago.
I stumpled upon a C code, where variables seem to be declared after the argument list of a function. I did not know that this was possible.
In the code, int r and int *a are declared right after the argument list of arr2int. How does this affect the local variables a and r of arr2int?
The actual reason why I want to understand the code is because if I let it run on my linux x86 a[1] = 1 at //MARKER when arr2int ist called the fist time.
But if I let it run ona an ARM-based omap4 dev board a[1]=0 and I dont know why there is a difference.
Could someone comment on this please?
long arr2int(a,r)
int r;
int *a;
{
int i;
long mul, result = 0, temp;
//MARKER
for (i=1; i<=r; i++) {
mul = 1;
temp = a[i]-1;
while (temp--)
mul = mul << 1;
result += mul;
}
return(result);
}
And the calling method:
void generateEncodingTable(){
register int i,j;
long temp;
int seed = 133757;
printf("\n[I] - Generating Encoding Table\n");
for (pattern = 0; pattern < 4096; pattern++) {
temp = pattern << 11; /* multiply information by X^{11} */
encoding_table[pattern] = temp + get_syndrome(temp);/* add redundancy */
}
decoding_table[0] = 0;
decoding_table[1] = 1;
temp = 1;
for (i=2; i<= 23; i++) {
temp *= 2;
decoding_table[get_syndrome(temp)] = temp;
}
a[1] = 1; a[2] = 2;
temp = arr2int(a,2);
decoding_table[get_syndrome(temp)] = temp;
for (i=1; i<253; i++) {
nextcomb(23,2,a);
temp = arr2int(a,2);
decoding_table[get_syndrome(temp)] = temp;
}
a[1] = 1; a[2] = 2; a[3] = 3;
temp = arr2int(a,3);
decoding_table[get_syndrome(temp)] = temp;
for (i=1; i<1771; i++) {
nextcomb(23,3,a);
temp = arr2int(a,3);
decoding_table[get_syndrome(temp)] = temp;
}
}
This is an old notation known as K & R (Kernighan & Ritchie, after Brian Kernighan and Dennis Ritchie) Notation for declaring the functions. If your compiler supports it, you can use it and it is same as declaring the function with ANSI notation.
As mention by others, this is an early style of function coding.
Following is a pitfall of that style. Be aware there is no type checking on passed parameters. It may explain your run time differences.
Say you declare a function
int foo(a,b,c);
All the compiler sees at that point is a function named "foo" taking 3 arguments and
returning an int. Thus usage checking is limited to that.
Let's assume sizeof(short) < sizeof(int) < sizeof(long) and the function is defined as
int foo(a,b,c)
int a;
long b;
int c;
{ /* code body */ }
Notice the following usage of foo
int d,e,f;
d = foo(1,2L,3);
e = foo((short)1,2L,3);
f = foo(1,2,3);
The first usages works fine, the right size integers are passed to foo.
The 2nd usages also works fine. The first argument is promoted to int size before the call, much like printf("%d", (short)2) promotes (short)2 to int before passing to printf().
The 3rd is a problem as the compiler does not know the second argument needs to be long. Thus the data passed to foo is not passed correctly. --> UB
This is an old C syntax. If your compiler can swallow it then it should work the same as if you have declared the functions the normal, ANSI way.
This is K&R C, i.e, the C language described by the first edition of The C Programming Language by Brian Kernighan and Dennis Ritchie. The second edition has turned to ANSI C(C89).
You shoul always use ANSI C style:
Rationale for International Standard - Programming Languages C 6.11.6 Function declarators
The characterization as obsolescent of the use ofthe “old style” function declarations and
definitions, that is, the traditional style not using prototypes, signals the Committee’s intent that the new prototype style should eventually replace the old style.
The gist of this case is that the new syntax addresses some of the most glaring weaknesses of the language defined in K&R, that the new style is superior to the old style on every count.
It is just a way of declaring types of function parameters:
void func (first_param, second_param)
int first_param;
int second_param;
{
// ...
}
is equal to
void func (int first_param, int second_param)
{
// ...
}
So I have already had a look at other posts with similar headings but none of the suggested answers are working for me.
I have a function that calculates the frequency of a char in a string:
int frequency(char *s, char c) {
int i;
for (i=0; s[i]; s[i]==c ? i++ : s++);
return i;
}
It works correctly but the compiler gives me the following error:
warning: pointer/integer type mismatch in conditional expression [enabled by default]
Could someone please explain why
Cheers
i++ is of type int, while the type of s++ is char *. In a conditional expression, you can't have two different types in the "then" and "else" branch, hence the warning.
Here the author of this code snippet was trying to be clever and short, but he simply got it wrong. I'd suggest rewriting this as
int frequency(const char *s, char c)
{
int i;
for (i = 0; s[i];)
if s[i] == c
i++;
else
s++;
return i;
}
Every expression must have a type. For this expression,
s[i]==c ? i++ : s++
it isn't clear what the type should be. i++ gives an integer, and s++ gives a char *. A char * is convertable to an int, which is basically the boolean value of whether the pointer is not null. So, by having the type of the expression be int, the compiler is able to make it work, but since this is very odd situation, you are getting the warning.
The code as written is using the parameter s both as a pointer to a character, and as a character array indexed by i. The for loop is being used to iterate over the string, but the start of the string is being moved when a matching character is not found.
This is very clever code. Clever code is seldom a good thing.
"It works" because the result of the expression s[i]==c ? i++ : s++ is not being used. Each branch performs an action, returning a value of a different type. Neither of those values is used in another expression.
I typically use for loops for performing a defined number of iterations. In this instance I think a while loop is more appropriate.
Using s as a pointer
int frequency(char *s, char c) {
int count = 0;
while (*s != 0) {
if (*s == c) {
count++;
}
s++;
}
return count;
}
Using s as a character array
int frequency(char s[], char c) {
int count = 0;
int current = 0;
while (s[current] != 0) {
if (s[current] == c) {
count++;
}
current++;
}
return count;
}