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

前端 未结 23 842
渐次进展
渐次进展 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:22

    Here you have to use, understand and explain the compiler logic, not the human logic (I know, you are a human, but here you must mimic the computer ...).

    When you write

    int *bar = &foo;
    

    the compiler groups that as

    { int * } bar = &foo;
    

    That is : here is a new variable, its name is bar, its type is pointer to int, and its initial value is &foo.

    And you must add : the = above denotes an initialization not an affectation, whereas in following expressions *bar = 2; it is an affectation

    Edit per comment:

    Beware : in case of multiple declaration the * is only related to the following variable :

    int *bar = &foo, b = 2;
    

    bar is a pointer to int initialized by the address of foo, b is an int initialized to 2, and in

    int *bar=&foo, **p = &bar;
    

    bar in still pointer to int, and p is a pointer to a pointer to an int initialized to the address or bar.

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

    There's a reason why K&R style favours int *p and Stroustrup style favours int* p; both are valid (and mean the same thing) in each language, but as Stroustrup put it:

    The choice between "int* p;" and "int *p;" is not about right and wrong, but about style and emphasis. C emphasized expressions; declarations were often considered little more than a necessary evil. C++, on the other hand, has a heavy emphasis on types.

    Now, since you're trying to teach C here, that would suggest you should be emphasising expressions more that types, but some people can more readily grok one emphasis quicker than the other, and that's about them rather than the language.

    Therefore some people will find it easier to start with the idea that an int* is a different thing than an int and go from there.

    If someone does quickly grok the way of looking at it that uses int* bar to have bar as a thing that is not an int, but a pointer to int, then they'll quickly see that *bar is doing something to bar, and the rest will follow. Once you've that done you can later explain why C coders tend to prefer int *bar.

    Or not. If there was one way that everybody first understood the concept you wouldn't have had any problems in the first place, and the best way to explain it to one person will not necessarily be the best way to explain it to another.

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

    A pointer is just a variable used to store addresses.

    Memory in a computer is made up of bytes (A byte consists of 8 bits) arranged in a sequential manner. Each byte has a number associated with it just like index or subscript in an array, which is called the address of the byte. The address of byte starts from 0 to one less than size of memory. For example, say in a 64MB of RAM, there are 64 * 2^20 = 67108864 bytes . Therefore the address of these bytes will start from 0 to 67108863 .

    Let’s see what happens when you declare a variable.

    int marks;

    As we know an int occupies 4 bytes of data (assuming we are using a 32-bit compiler) , so compiler reserves 4 consecutive bytes from memory to store an integer value. The address of the first byte of the 4 allocated bytes is known as the address of the variable marks . Let’s say that address of 4 consecutive bytes are 5004 , 5005 , 5006 and 5007 then the address of the variable marks will be 5004 .

    Declaring pointer variables

    As already said a pointer is a variable that stores a memory address. Just like any other variables you need to first declare a pointer variable before you can use it. Here is how you can declare a pointer variable.

    Syntax: data_type *pointer_name;

    data_type is the type of the pointer (also known as the base type of the pointer). pointer_name is the name of the variable, which can be any valid C identifier.

    Let’s take some examples:

    int *ip;
    
    float *fp;
    

    int *ip means that ip is a pointer variable capable of pointing to variables of type int . In other words, a pointer variable ip can store the address of variables of type int only . Similarly, the pointer variable fp can only store the address of a variable of type float . The type of variable (also known as base type) ip is a pointer to int and type of fp is a pointer to float . A pointer variable of type pointer to int can be symbolically represented as ( int * ) . Similarly, a pointer variable of type pointer to float can be represented as ( float * )

    After declaring a pointer variable the next step is to assign some valid memory address to it. You should never use a pointer variable without assigning some valid memory address to it, because just after declaration it contains garbage value and it may be pointing to anywhere in the memory. The use of an unassigned pointer may give an unpredictable result. It may even cause the program to crash.

    int *ip, i = 10;
    float *fp, f = 12.2;
    
    ip = &i;
    fp = &f;
    

    Source: thecguru is by far the simplest yet detailed explanation I have ever found.

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

    It was already noted that * has multiple roles.

    There's another simple idea that may help a beginner to grasp things:

    Think that "=" has multiple roles as well.

    When assignment is used on the same line with declaration, think of it as a constructor call, not an arbitrary assignment.

    When you see:

    int *bar = &foo;
    

    Think that it's nearly equivalent to:

    int *bar(&foo);
    

    Parentheses take precendence over asterisk, so "&foo" is much more easily intuitively attributed to "bar" rather than "*bar".

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

    "maybe writing it as int* bar makes it more obvious that the star is actually part of the type, not part of the identifier." So I do. And I say, that it is somesing like Type, but only for one pointer name.

    " Of course this runs you into different problems with unintuitive stuff like int* a, b."

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

    The source of confusion arises from the fact that * symbol can have different meanings in C, depending upon the fact in which it is used. To explain the pointer to a beginner, the meaning of * symbol in different context should be explained.

    In the declaration

    int *bar = &foo;  
    

    the * symbol is not the indirection operator. Instead, it helps to specify the type of bar informing the compiler that bar is a pointer to an int. On the other hand, when it appears in a statement the * symbol (when used as a unary operator) performs indirection. Therefore, the statement

    *bar = &foo;
    

    would be wrong as it assigns the address of foo to the object that bar points to, not to bar itself.

    0 讨论(0)
提交回复
热议问题