Can someone explain variables declaration in C - c

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.

Related

Global Array Issues Not Updating, C Programming

I have a program distributed across a number of files. There are a number of functions which need access to a global array. The issue I'm having is that I don't know the size of the array before the program starts. It opens up a file and then downloads a number of points, and then the array is created with a corresponding size. But for the array to be global, it needs to be declared outside of the main function i.e. before I know the number of points.
What I've tried to do right now is:
file1.c:
#include <stdio.h>
#include "file3.h"
int useful[];
int main()
{
int useful[10];
int i;
for (i = 0; i < 10; i++) {
useful[i] = i+1;
}
SPN();
return 0;
}
file2.c:
#include <stdio.h>
#include "file3.h"
void SPN() {
int i;
for (i = 0; i < 10; i++) {
printf("%i\n", useful[i]);
}
}
file3.h:
extern int useful[];
extern void SPN();
What I'm getting in output is just a bunch of 0s. At first I was thinking that the second int useful[... in file1.c creates a new array with a different internal name, but that doesn't seem to make any sense considering that no segmentation fault is triggered by SPN() when it tries to access memory outside the arrays bounds (if useful[] creates an array and isn't changed, it has default size 1 i.e. < 10). Help?
The int useful[10]; isn't initializing the global int useful[]; or anything like that. It's a new variable, and with the loop here
for (i = 0; i < 10; i++) {
useful[i] = i+1;
}
You're modifying the second useful without touching the global one. This is then discarded at the end of the function.
Instead have a global variable like this:
int *useful;
And initialize it this way:
useful = malloc(sizeof(int)*10);
The declaration of useful inside the main is shadowing the external one.
This means that the values that you think are inserting (in the main) in the global variable are actually going into the local variable.
Take a look at the following article about shadowing for more info.
It might also be interesting to look at scope rules in C.

why do I need the curly braces here?

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).

what is "error: variable-sized object may not be initialized"?

I'm trying to fill an array with numbers from 1-100 with this code:
#include <stdio.h>
int main()
{
int num[100];
int i = 0;
for (i = 0; i < 100; i++)
{
int num[i] = i+1;
}
}
but I'm getting this error:
c:18:13: error: variable-sized object may not be initialized
I'm still relatively new to programming so I'm not sure what this means. Can you tell me?
Replace this
int num[i] = i+1;
For this:
num[i] = i+1;
You already declare the array on the top int num[100];
First you declare the array, and then you iterate over it inside the loop.
Since you are new, it is preferable you start by reading a good book about the subject my recommendation.
The problem is the int in int num[i] = i+1. The compiler thinks you're trying to declare a new array (also called num) with i elements in it (that's the variable-sized object part). Just remove the int from that line.
You are declaring the array again in the loop:
int num[i] = i+1;
Anyway, this is the error in your code but the problem for the compiler is not there: it gives you that error because that's not a valid declaration with initialization for an array. If you just write int num[i]; the code it's valid code and it will compile without error (well, only from C99, old C89 doesn't support variable-length arrays). This is what the compiler recognizes and tries to report.

What is the problem with the following piece of code?

This piece of code seems to be creating some troubles while compiling. Any explanation?
int i =20;
int maxlen = i;
int main()
{
int j = i;
printf("i=%d , j=%d\n", i , j);
}
In C, you can't initialize global variables using non-constant expressions. Initializing maxlen to i fails because i is not a constant expression. It's part of the C standard.
Why not #define a constant?
#define MAXLEN 20
You can only use compile-time constants when initializing a variable at that scope. Try:
int i = 20;
int maxlen;
int main()
{
maxlen = i; // assign within the scope of a function
int j = i;
printf("i=%d , j=%d\n", i , j);
}
This Code is Invalid in C but valid in C++:
C - http://www.ideone.com/mxgMo
Error Reason -: initializer element is not constant
C++ - http://www.ideone.com/XzoeU
Works.
Because:
The C++ Standard states:
3.6.1 Main function [basic.start.main]
1 A program shall contain a global function called main, which is the designated start of the program. It is implementation defined whether a program in a freestanding environment is required to define a main function. [ Note: in a freestanding environment, start-up and termination is implementation-defined; start-up contains the execution of constructors for objects of namespace scope with static storage duration; termination contains the execution of destructors for objects with static storage duration. —end note ]
However, C99 says this:
56.7.8 Initialization
4 All the expressions in an initializer for an object that has static storage duration
shall be constant expressions or string literals.
So not just the code you posted, but something like this will also be invalid in C:
#include<stdio.h>
int needint(void);
int i =needint();
int needint(void)
{
return 1;
}
int main()
{
int j = i;
printf("i=%d , j=%d\n", i , j);
}
See here.

Passing pointers of arrays in C

So I have some code that looks like this:
int a[10];
a = arrayGen(a,9);
and the arrayGen function looks like this:
int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
arrAddr[counter] = gen(maxNum);
counter++;
}
return arrAddr;
}
Right now the compilier tells me "warning: passing argument 1 of ‘arrayGen’ makes integer from pointer without a cast"
My thinking is that I pass 'a', a pointer to a[0], then since the array is already created I can just fill in values for a[n] until I a[n] == '\0'. I think my error is that arrayGen is written to take in an array, not a pointer to one. If that's true I'm not sure how to proceed, do I write values to addresses until the contents of one address is '\0'?
The basic magic here is this identity in C:
*(a+i) == a[i]
Okay, now I'll make this be readable English.
Here's the issue: An array name isn't an lvalue; it can't be assigned to. So the line you have with
a = arrayGen(...)
is the problem. See this example:
int main() {
int a[10];
a = arrayGen(a,9);
return 0;
}
which gives the compilation error:
gcc -o foo foo.c
foo.c: In function 'main':
foo.c:21: error: incompatible types in assignment
Compilation exited abnormally with code 1 at Sun Feb 1 20:05:37
You need to have a pointer, which is an lvalue, to which to assign the results.
This code, for example:
int main() {
int a[10];
int * ip;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
return 0;
}
compiles fine:
gcc -o foo foo.c
Compilation finished at Sun Feb 1 20:09:28
Note that because of the identity at top, you can treat ip as an array if you like, as in this code:
int main() {
int a[10];
int * ip;
int ix ;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
for(ix=0; ix < 9; ix++)
ip[ix] = 42 ;
return 0;
}
Full example code
Just for completeness here's my full example:
int gen(int max){
return 42;
}
int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
arrAddr[counter] = gen(maxNum);
counter++;
}
return arrAddr;
}
int main() {
int a[10];
int * ip;
int ix ;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
for(ix=0; ix < 9; ix++)
ip[ix] = 42 ;
return 0;
}
Why even return arrAddr? Your passing a[10] by reference so the contents of the array will be modified. Unless you need another reference to the array then charlies suggestion is correct.
Hmm, I know your question's been answered, but something else about the code is bugging me. Why are you using the test against '\0' to determine the end of the array? I'm pretty sure that only works with C strings. The code does indeed compile after the fix suggested, but if you loop through your array, I'm curious to see if you're getting the correct values.
I'm not sure what you are trying to do but the assignment of a pointer value to an array is what's bothering the compiler as mentioned by Charlie. I'm curious about checking against the NUL character constant '\0'. Your sample array is uninitialized memory so the comparison in arrayGen isn't going to do what you want it to do.
The parameter list that you are using ends up being identical to:
int* arrayGen(int *arrAddr, int maxNum)
for most purposes. The actual statement in the standard is:
A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
If you really want to force the caller to use an array, then use the following syntax:
void accepts_pointer_to_array (int (*ary)[10]) {
int i;
for (i=0; i<10; ++i) {
(*ary)[i] = 0; /* note the funky syntax is necessary */
}
}
void some_caller (void) {
int ary1[10];
int ary2[20];
int *ptr = &ary1[0];
accepts_pointer_to_array(&ary1); /* passing address is necessary */
accepts_pointer_to_array(&ary2); /* fails */
accepts_pointer_to_array(ptr); /* also fails */
}
Your compiler should complain if you call it with anything that isn't a pointer to an array of 10 integers. I can honestly say though that I have never seen this one anywhere outside of various books (The C Book, Expert C Programming)... at least not in C programming. In C++, however, I have had reason to use this syntax in exactly one case:
template <typename T, std::size_t N>
std::size_t array_size (T (&ary)[N]) {
return N;
}
Your mileage may vary though. If you really want to dig into stuff like this, I can't recommend Expert C Programming highly enough. You can also find The C Book online at gbdirect.
Try calling your parameter int* arrAddr, not int arrAddr[]. Although when I think about it, the parameters for the main method are similar yet that works. So not sure about the explanation part.
Edit: Hm all the resources I can find on the internet say it should work. I'm not sure, I've always passed arrays as pointers myself so never had this snag before, so I'm very interested in the solution.
The way your using it arrayGen() doesn't need to return a value. You also need to place '\0' in the last element, it isn't done automatically, or pass the index of the last element to fill.
#jeffD
Passing the index would be the preferred way, as there's no guarantee you won't hit other '\0's before your final one (I certainly was when I tested it).

Resources