How to explain C pointers (declaration vs. unary operators) to a beginner?

前端 未结 23 839
渐次进展
渐次进展 2020-11-30 18:08

I have had the recent pleasure to explain pointers to a C programming beginner and stumbled upon the following difficulty. It might not seem like an issue at all if you alre

相关标签:
23条回答
  • 2020-11-30 18:08

    tl;dr:

    Q: How to explain C pointers (declaration vs. unary operators) to a beginner?

    A: don't. Explain pointers to the beginner, and show them how to represent their pointer concepts in C syntax after.


    I have had the recent pleasure to explain pointers to a C programming beginner and stumbled upon the following difficulty.

    IMO the C syntax isn't awful, but isn't wonderful either: it's neither a great hindrance if you already understand pointers, nor any help in learning them.

    Therefore: start by explaining pointers, and make sure they really understand them:

    • Explain them with box-and-arrow diagrams. You can do it without hex addresses, if they're not relevant, just show the arrows pointing either to another box, or to some nul symbol.

    • Explain with pseudocode: just write address of foo and value stored at bar.

    • Then, when your novice understands what pointers are, and why, and how to use them; then show the mapping onto C syntax.

    I suspect the reason the K&R text doesn't provide a conceptual model is that they already understood pointers, and probably assumed every other competent programmer at the time did too. The mnemonic is just a reminder of the mapping from the well-understood concept, to the syntax.

    0 讨论(0)
  • 2020-11-30 18:09

    This issue is somewhat confusing when starting to learn C.

    Here are the basic principles that might help you get started:

    1. There are only a few basic types in C:

      • char: an integer value with the size of 1 byte.

      • short: an integer value with the size of 2 bytes.

      • long: an integer value with the size of 4 bytes.

      • long long: an integer value with the size of 8 bytes.

      • float: a non-integer value with the size of 4 bytes.

      • double: a non-integer value with the size of 8 bytes.

      Note that the size of each type is generally defined by the compiler and not by the standard.

      The integer types short, long and long long are usually followed by int.

      It is not a must, however, and you can use them without the int.

      Alternatively, you can just state int, but that might be interpreted differently by different compilers.

      So to summarize this:

      • short is the same as short int but not necessarily the same as int.

      • long is the same as long int but not necessarily the same as int.

      • long long is the same as long long int but not necessarily the same as int.

      • On a given compiler, int is either short int or long int or long long int.

    2. If you declare a variable of some type, then you can also declare another variable pointing to it.

      For example:

      int a;

      int* b = &a;

      So in essence, for each basic type, we also have a corresponding pointer type.

      For example: short and short*.

      There are two ways to "look at" variable b (that's what probably confuses most beginners):

      • You can consider b as a variable of type int*.

      • You can consider *b as a variable of type int.

      Hence, some people would declare int* b, whereas others would declare int *b.

      But the fact of the matter is that these two declarations are identical (the spaces are meaningless).

      You can use either b as a pointer to an integer value, or *b as the actual pointed integer value.

      You can get (read) the pointed value: int c = *b.

      And you can set (write) the pointed value: *b = 5.

    3. A pointer can point to any memory address, and not only to the address of some variable that you have previously declared. However, you must be careful when using pointers in order to get or set the value located at the pointed memory address.

      For example:

      int* a = (int*)0x8000000;

      Here, we have variable a pointing to memory address 0x8000000.

      If this memory address is not mapped within the memory space of your program, then any read or write operation using *a will most likely cause your program to crash, due to a memory access violation.

      You can safely change the value of a, but you should be very careful changing the value of *a.

    4. Type void* is exceptional in the fact that it doesn't have a corresponding "value type" which can be used (i.e., you cannot declare void a). This type is used only as a general pointer to a memory address, without specifying the type of data that resides in that address.

    0 讨论(0)
  • 2020-11-30 18:11

    Basically Pointer is not a array indication. Beginner easily thinks that pointer looks like array. most of string examples using the

    "char *pstr" it's similar looks like

    "char str[80]"

    But, Important things , Pointer is treated as just integer in the lower level of compiler.

    Let's look examples::

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv, char **env)
    {
        char str[] = "This is Pointer examples!"; // if we assume str[] is located in 0x80001000 address
    
        char *pstr0 = str;   // or this will be using with
        // or
        char *pstr1 = &str[0];
    
        unsigned int straddr = (unsigned int)pstr0;
    
        printf("Pointer examples: pstr0 = %08x\n", pstr0);
        printf("Pointer examples: &str[0] = %08x\n", &str[0]);
        printf("Pointer examples: str = %08x\n", str);
        printf("Pointer examples: straddr = %08x\n", straddr);
        printf("Pointer examples: str[0] = %c\n", str[0]);
    
        return 0;
    }
    

    Results will like this 0x2a6b7ed0 is address of str[]

    ~/work/test_c_code$ ./testptr
    Pointer examples: pstr0 = 2a6b7ed0
    Pointer examples: &str[0] = 2a6b7ed0
    Pointer examples: str = 2a6b7ed0
    Pointer examples: straddr = 2a6b7ed0
    Pointer examples: str[0] = T
    

    So, Basically, Keep in mind Pointer is some kind of Integer. presenting the Address.

    0 讨论(0)
  • 2020-11-30 18:12

    For your student to understand the meaning of the * symbol in different contexts, they must first understand that the contexts are indeed different. Once they understand that the contexts are different (i.e. the difference between the left hand side of an assignment and a general expression) it isn't too much of a cognitive leap to understand what the differences are.

    Firstly explain that the declaration of a variable cannot contain operators (demonstrate this by showing that putting a - or + symbol in a variable declaration simply causes an error). Then go on to show that an expression (i.e. on the right hand side of an assignment) can contain operators. Make sure the student understands that an expression and a variable declaration are two completely different contexts.

    When they understand that the contexts are different, you can go on to explain that when the * symbol is in a variable declaration in front of the variable identifier, it means 'declare this variable as a pointer'. Then you can explain that when used in an expression (as a unary operator) the * symbol is the 'dereference operator' and it means 'the value at the address of' rather than its earlier meaning.

    To truly convince your student, explain that the creators of C could have used any symbol to mean the dereference operator (i.e. they could have used @ instead) but for whatever reason they made the design decision to use *.

    All in all, there's no way around explaining that the contexts are different. If the student doesn't understand the contexts are different, they can't understand why the * symbol can mean different things.

    0 讨论(0)
  • 2020-11-30 18:13

    The 2nd statement int *bar = &foo; can be viewed pictorially in memory as,

       bar           foo
      +-----+      +-----+
      |0x100| ---> |  1  |
      +-----+      +-----+ 
       0x200        0x100
    

    Now bar is a pointer of type int containing address & of foo. Using the unary operator * we deference to retrieve the value contained in 'foo' by using the pointer bar.

    EDIT: My approach with beginners is to explain the memory address of a variable i.e

    Memory Address: Every variable has an address associated with it provided by the OS. In int a;, &a is address of variable a.

    Continue explaining basic types of variables in C as,

    Types of variables: Variables can hold values of respective types but not addresses.

    int a = 10; float b = 10.8; char ch = 'c'; `a, b, c` are variables. 
    

    Introducing pointers: As said above variables, for example

     int a = 10; // a contains value 10
     int b; 
     b = &a;      // ERROR
    

    It is possible assigning b = a but not b = &a, since variable b can hold value but not address, Hence we require Pointers.

    Pointer or Pointer variables : If a variable contains an address it is known as a pointer variable. Use * in the declaration to inform that it is a pointer.

    • Pointer can hold address but not value
    • Pointer contains the address of an existing variable.
    • Pointer points to an existing variable
    
    0 讨论(0)
  • 2020-11-30 18:14

    I'd rather read it as the first * apply to int more than bar.

    int  foo = 1;           // foo is an integer (int) with the value 1
    int* bar = &foo;        // bar is a pointer on an integer (int*). it points on foo. 
                            // bar value is foo address
                            // *bar value is foo value = 1
    
    printf("%p\n", &foo);   // print the address of foo
    printf("%p\n", bar);    // print the address of foo
    printf("%i\n", foo);    // print foo value
    printf("%i\n", *bar);   // print foo value
    
    0 讨论(0)
提交回复
热议问题