C Programming Variable Scope and Pointers

Discussion in 'Mac Programming' started by cybrscot, Apr 4, 2011.

  1. macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #1
    Okay, I'm finally getting to something totally new to me in my "Learn C on a Mac" book.

    The book says that in the following code, the error is when the function DrawDots() tries to reference the variable numDots.

    Where can I recognize that DrawDots() is trying to reference numDots??
    I see that numDots = 500; is directly above DrawDots(); but they are on two separate lines, and i don't see how one has anything to do with the other? Where is DrawDots(); trying to reference numDots;? Each line makes no reference of the other.


    Code:
    #include <stdio.h>
    
    int main (int argc, const char * argv[]) {
    	int numDots;
    	
    	numDots = 500;
    	DrawDots();
    	
    	return 0;
    }
    	
    void DrawDots( void ) {
    	int i;
    	
    	for ( i = 1; i <= numDots; i++ )
    		printf (".");
    		
    }	
     
  2. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #2
    In the for loop numDots is in the condition. This won't compile because there is no variable numDots in this scope.

    -Lee
     
  3. thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #3
    But numDots is declared as an int variable at the top of the program, just like all other programs I've written so far???
     
  4. macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #4
    'numDots' is declared as a local variable within the function main and thus is only assessable from within 'main'.
     
  5. macrumors regular

    Joined:
    Nov 24, 2006
    Location:
    The Netherlands
    #5
    It's declared within main, so in the main scope. Declare it outside of main if you want it to be global :)
     
  6. macrumors member

    AustinZ

    Joined:
    Aug 6, 2008
    #6
    numDots was declared in the main() function so only code inside the main() function can see that variable. To every other function, it's as if numDots didn't exist.

    If you really need the function DrawDots() to know what numDots is, declare numDots as a global variable (which means every function will be able to see it and change its value) or, better yet, pass it into the DrawDots() function as an argument like such:

    Code:
    #include <stdio.h>
    [b]void DrawDots( int nDots );[/b]
    
    int main (int argc, const char * argv[]) {
    	int numDots;
    	
    	numDots = 500;
    	[b]DrawDots(numDots);[/b]
    	
    	return 0;
    }
    	
    [b]void DrawDots( int nDots ) {[/b]
    	int i;
    	
    	[b]for ( i = 1; i <= nDots; i++ )[/b]
    		printf (".");
    		
    }
    
     
  7. thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #7
    So is a "scope" essentially another way of saying "function"?? Two prev posters have mentioned scope like it's a "place" in my program, ie, "not in this scope", or the "main scope" Which is like saying not in "main's function", or declare the variable outside the "main function"

    If the variable is located inside a specific function, it's only available to be referenced in that function, if it's outside a function, it can be referenced anywhere in the program, correct?

    Lastly, I still get a bit confused with all the terminology and differences between functions, arguments, statements, scope, strings, etc.

    Programs are made up of functions, and functions are made up of stmts, how can I recognize a function? Is it always in the form....

    name () {body} ??

    I just want to be able to quickly look at my code and identify which part is the function.
     
  8. macrumors member

    AustinZ

    Joined:
    Aug 6, 2008
    #8
    The function is always in the form, like you said:

    returntype functionName(arguments) {
    (stuff...)
    }

    The body of the function *always* starts with {, and ends with }.

    'scope' isn't just a function. It's basically where in the program your variable is valid. For a particular variable, scope can be the entire program, a single function, or a portion of a function (or other things as well). An example of the last statement is this function:

    Code:
    void myFunction() {
    
       for (int i=0; i<10; ++i) {
         //do stuff
         printf("right now i is: %d\n", i);
       }
    
       printf("The final value of i is: %d\n", i);
    
    }
    
    In this case your code will refuse to compile. The reason is that the scope for the variable 'i' is only within the for loop. In other words, the way i is defined you can only access or modify i within the for loop. This code tries to print the value of i ('The final value of i...'), but the printf function is outside the for loop, in other words, outside the scope of i.
     
  9. macrumors regular

    Joined:
    Nov 24, 2006
    Location:
    The Netherlands
    #9
    like you said functions look like <returntype> name (arguments) { body }

    Now, whenever you type a { you enter a new scope.

    Take this example:

    Code:
    #include <stdio.h>
    
    int main (int *argc, char *argv[0]) {
    
     int a = 5; // a will be 5
     printf("%d\n",a); //we print a
     
     {   // we enter a NEW scope here. a is still 5
      int a = 10;  // in the NEW scope we declare a NEW a which will be 10
      printf("%d\n",a); //we print a
     } // end of scope. the NEW a will now go out of scope, as if it never existed
      printf("%d\n",a); // we print a (which will be the original a as this statement is in the same outerscope as the original a
    };
    
    
    this prints:

    Code:
    5
    10
    5
    
    Why ? Because the a in the innerscope is not the same as the one in the main scope.
     
  10. dmi
    macrumors regular

    Joined:
    Dec 21, 2010
    #10
    Your are correct in saying that the line
    Code:
    	numDots = 500;
    
    and the reference
    Code:
    	for ( i = 1; i <= numDots; i++ )
    
    in DrawDots have nothing to do with each other,
    because each is in a different scope.

    A name declared in a block is local to that block; it has block scope. Its potential scope begins at its
    point of declaration and ends at the end of its block.

    So the error is that the loop in DrawDots tries to make reference to an undeclared symbol.
     
  11. macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #11
    The concept of scope has been explained above, but here's my go at an explanation.

    Scope is a place. It's the area in your program where an identifier is visible, that is the area where the identifier can be validly used.

    The scope of a local variable, that is the area in your program where you can validly refer to that variable, starts immediately after where the local variable is declared up to immediately before the first closing brace at the next higher level as the local variable's declaration.

    Consider the following code (with line numbers prefixed):

    Code:
     1: void functionA( void );
     2:
     3: int main( void ) {
     4:   int local_var = 0;
     5:   if (local_var == 0) {
     6:      local_var = 1;
     7:      int inner_var = 0;
     8:      functionA();
     9:   }
    10:   local_var = 2;
    11: }
    12:
    13: void functionA( void ) {
    14: }
    
    
    The scope of local_var is from immediately after line 4 where it's declared, down to immediately before line 11. That is, local_var can be validly used anywhere between these two points in the program. You cannot use it on or before line 4 and you cannot use it on or after line 11. In particular, it can't be used anywhere inside the definition of functionA on lines 13 and 14.

    Notice that local_var's scope doesn't end immediately before line 9. This is because the closing brace on line 9 is at the same level as local_var, not at the next highest level.

    Notice the declaration of inner_var on line 7? It's scope is from immediately after line 7 up to immediately before line 9. So it couldn't be used on line 10, for example.

    Take note that inner_var also couldn't be used on line 6 even though it's within the same set of { } as inner_var. This is because it's before inner_var's declaration.

    There a few different "types" of scope in C. In this example and your example, we've been dealing with local scope.

    There's also global scope. Global scope happens when an identifier is declared outside of any function. For example, functionA is in global scope. That's right, functions have scope too, not just variables.

    Global scope starts from immediately after the declaration, just like local scope, except it goes all the way down to the end of the file. Actually it's scope is even greater than that, but you'll learn about that when you learn about coding programs that are made up of multiple .c files.
     
  12. Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #12
    And that is the other problem with the code posted in the first post.

    By the time the compiler is trying to compile main, DrawDots is not defined yet in that scope so it will not succeed.

    You either need to do as AustinZ did and define a prototype for DrawDots first (either in your .c file or in a .h file) or move the code for DrawDots above main.

    Otherwise you have a situation like:

    Code:
    int a;
    a=b;
    int b;
    By the time the assignment (function call) is done, the variable (function) has yet to be defined.

    B
     
  13. thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #13

    So, int, float, and void are all return types? Again the language threw me off, my first book, C Programming by KN King only said that "all variables are of a type", and int and float were the two "types" I've learned so far.

    So I've always known them only as types, now we're talking about "returntype". Everything with computers is always so specific and literal, but in C, it's when we've used different terminology to describe the same thing that's slowing me down. Returntypes are the same thing as types? I gather that to be true based on when I looked on Google, it listed void, int, float and others among return types.
     
  14. Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #14
    They can be.

    A function generally returns something. The data type of that something is the function's return type. For example: the function main typically returns an int. This is why we declare it as "int main(void)" and it is also why main ends with "return 0;".

    In general, a function can return any valid C data type, including those you have defined yourself using "struct" or "typedef".

    In cases where a function doesn't return anything (which would be called a subroutine in other languages) C provides the "void" data type as a placeholder to say: This function doesn't return anything.

    B
     
  15. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #15
    There are types. Different things have types. One such thing is a variable, the first thing you're going to run into. Another is a function's return type. Basically when you run the function, it's going to return a value with that type. Every expression evaluates to a certain type, too. So x * y will evaluate to an int if x and y are ints. You can then assign that expression to another int variable to store its value. Even a = 6 evaluates to an int with value 6, so you can do: a = b = c = 7; and set all of the variables to the same thing, because c = 7 evaluates to 7, and so on. So an expression has a type that it evaluates to, variables have types, functions have types (that they return).

    These types are extremely important because in the computer's memory, all of the data is just a bunch of 0s and 1s. The type tells you how many of those 0s and 1s to interpret, and in what manner to interpret them. The same patterns of 0s and 1s could be interpreted as different things based on the type. It also determines what sort of operation is really going to be performed. To a computer multiplying two ints is a much different operation than multiplying two floats.

    As has been stated a number of times here, what an author thinks is important and how they present data, is going to be based on their knowledge, understanding, and how they believe information is best presented. This may not fit your learning style, and without being able to ask the author questions, you're stuck with your interpretation of what they've presented. Sometimes re-reading will give you a better understanding and different interpretation, but not always, especially if you don't have any additional information to bring to the table.

    -Lee
     
  16. thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #16
    I think I got it, int, float, void are types, whatever "type" I expect as the result of my function, ie the type that it "returns" is my "returntype"
    Okay, so when I write a function, it should start with a returntype, which......is the type that corresponds to what the final value of my function is expected to be? If I expect the value of my function to be, say, 24 for example, since 24 is an int, my function will start with returntype int?

    Do I have a ding ding ding here??

    The book shows many examples of func prototypes with (void), assuming the above that I wrote is correct, do I use the int in my function prototype? Or do I only use void?

    Since below, the main exits with a value of 0, 0 is an int. so why don't we give the compiler a heads up and use int, rather than void in the f.proto??
    Book shows..

    Code:
    void SayHello ( void ) ;
    
    int main (int argc, cosnt char * argv[]) {
           SayHello();
    
    return 0;
    }
    void SayHello(void) {
        printf("Hello, world!\n");
    }
     
  17. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #17
    If you want 24 treated as an int and not some other type, then the return type would be int. main is "special". It is the entry-point to every program. The compiler knows what type it should be. Also, while we've seen examples of it on the forum, it is rare for main to be called by other functions. This means that when the compiler is going through the rest of your code it is unlikely to find a use of main and need to know what sort of thing it is. The purpose of prototypes is to tell the compiler "trust me, this function will look like this" so when it finds it being used it knows what that thing should be because you told it with a prototype.

    -Lee
     
  18. macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #18
    No because C has the static keyword which means that anything declared with that keyword is only available within that source file. It is sometimes called file scope.

    Basically you have global scope (available to the whole program and in general a bad idea for variables), local scope (available just within a certain function or block) and file scope (available just within that compilation unit, i.e file).
     
  19. Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #19
    Because you care about each individual function. In a way it's a matter of scope.

    main will generally return int. This is the expected behavior. lee1210 already touched on this.

    Lets take a different example.

    Code:
    #include <stdio.h>
    
    double cubeit ( double x ) ;
    
    int main (int argc, cosnt char * argv[]) {
    
        double a = 100;
    
        double c = cubeit(a);
    
        printf ("The cube of %g is %g",a, c);
    
        return 0;
    }
    
    double cubeit ( double x )  {
        double cube = x*x*x;
        return cube;
    }
    The compiler needs to know what to do with the return value when it calls cubeit. It doesn't matter at that point that main will eventually return an int. It needs to know how to interpret the return value of cubeit so it can stuff that in the variable "c".

    Up until you need to split your code into multiple files or run into mutually recursive functions I would suggest doing this instead.

    Code:
    #include <stdio.h>
    
    double cubeit ( double x )  {
        double cube = x*x*x;
        return cube;
    }
    
    int main (int argc, cosnt char * argv[]) {
    
        double a = 100;
    
        double c = cubeit(a);
    
        printf ("The cube of %g is %g",a, c);
    
        return 0;
    }
    
    Then just remember if you want to move cubeit to another file, you need to replace it with a function prototype.

    B
     
  20. macrumors 6502a

    Joined:
    Oct 26, 2010
    #20
    A way I understand scope is this -

    Variables only exist within a set of brackets (the { } brackets).

    So in your example, numDots only exists between the brackets for main.

    Code:
    int main (int argc, const char * argv[]) {
    	int numDots;
    	
    	numDots = 500;
    	DrawDots();
    	
    	return 0;
    }
    	
    void DrawDots( void ) {
    	int i;
    	
    	for ( i = 1; i <= numDots; i++ )
    		printf (".");
    		
    }
    for example, if you were to change main to

    Code:
    int main (int argc, char * const argv[]) {
    	{
    	int numDots;
    	}
    	numDots = 500;
    	DrawDots();
    	
    	return 0;
    }
    
    numDots would only exist within the closest set of brackets, and so when it hit the } bracket (first one) it would no longer exist, and so the next line will give an error trying to find numDots.

    Unless passed between functions, variables only exist within the scope of the function - so for example if you tried to use "i" in main, you would have the same problem.

    Because of this idea though you can do stuff like the following if you wanted to for some reason
    Code:
    int main (int argc, char * const argv[]) {
    	{
    		int numDots;
    	}
    	{
    		int numDots;
    	}
    	{
    		int numDots;
    	}
    	{
    		int numDots;
    	}
    	{
    		int numDots;
    	}
    	int numDots;
    	numDots = 500;
    	DrawDots();
    	
    	return 0;
    }
    Also your title references Pointers - they make things somewhat more complicated :)
     
  21. macrumors 68000

    Sydde

    Joined:
    Aug 17, 2009
    #21
    Technically, every function does return some value. If you specify a return value in the function definition, you must include a return theType; in your function, otherwise the compiler will cough. The void type simply tells the compiler that the return value will be undefined and your function will not have a return statement specifying it.

    Note that printf() specifies a return value of int, which typically gets ignored when printing to the console (look up the printf() man page to understand what the return value is used for). Just as you can ignore a return value, theoretically you could obtain a void return value and use it (if you can get the compiler to accept such code), but you have no way of guessing what that void value might be or how it might be useful.
     
  22. thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #22
    Okay, I fully understand scope, it's a pretty easy concept actually. It's "where" the variable is available to be used. No problem here.

    I've also finished reading both books on pointers, I feel pretty good about what they are, how to declare them, the address and indirection operators, and what they do.

    What I don't understand (as I don't with many things I'm learning from programming) I don't understand how I will know I need to use a pointer!!!!

    If I'm writing a program to do something, how will I know, "okay, I'll need pointers in this program" That's the biggest difficulty I have in understanding some things. I know what they do, and how they do it, but I can't presently think of a program I could write that it would be necessary to take advantage of pointers. Any suggestions? Like, "if you want to do this, you'll need pointers so that you can do this"

    I just don't understand their relevance yet. The books don't do a great job in giving a variety of scenarios in which one would want to use a pointer, I think that's just about as important to teach a beginner as what pointers are and how they work.
     
  23. macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #23
    It is pretty straight forward. When you allocate memory using one of the malloc family functions (malloc(), calloc() etc etc) it returns a void pointer which points to the allocated memory. This is the most common use of pointers which is to access dynamically allocated memory. Don't forget to free() the memory when you are done with it though.

    Since C is a pass by value language (i.e everything you pass into a function is copied), you might want to pass the address of particularly large data structures rather than the whole data structure itself as that would be a very expensive operation. Therefore functions often take pointers so that they simply need to copy the address rather than the data itself.

    The other common use of pointers is that you can pass a pointer to a pointer into a function and use it as a second return value if you want. For instance the function itself could return an int indicating the type of error that occurred and the a function argument which could be a struct might also be set to contain some important information about the error (for instance the author of the function might have a field which tells you the exact time the error occurred). That was a made up example but it should explain another use.
     
  24. macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #24
    Don't worry about this toooo much. Mostly this comes with the experience of creating actual programs. This experience will give to the instinct to recognise when you need to use a particular tool or combination of tools. For now just become as familiar and comfortable with each of the tools as possible.
     
  25. balamw, Apr 6, 2011
    Last edited: Apr 6, 2011

    Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #25
    It'll hit you hard in the next chapter of both books when they introduce arrays after pointers. It seems like King already gave you arrays, but will come back to it now that you have pointers. Learn C on the Mac will introduce malloc and free in the chapter after that. King will wait until Chapter 17 to introduce malloc.

    Patience. You're not done with either book, they have to introduce a concept before they show you how to put it together with something else to build something larger.

    B
     

Share This Page