Deep understanding of the mysteries of C language pointers

Source: Internet
Author: User
Tags arithmetic numeric value
A pointer is a special variable that is stored in a value that is interpreted as an address in memory. To figure out a pointer needs to figure out four aspects of the pointer: the type of the pointer, the type the pointer is pointing to, the value of the pointer, the memory area that the pointer points to, and the memory area occupied by the pointer itself. Let's explain separately.
Let's declare a few pointers to do the example:
Example one:
(1) Int*ptr;
(2) Char*ptr;
(3) Int**ptr;
(4) int (*PTR) [3];
(5) int* (*PTR) [4];
  
Type of pointer
From a grammatical point of view, you simply remove the pointer name from the pointer declaration statement, and the rest is the type of pointer. This is the type that the pointer itself has. Let's look at the types of each pointer in example one:
(1) The type of int*ptr;//pointer is int*
(2) The type of char*ptr;//pointer is char*
(3) The type of int**ptr;//pointer is int**
(4) int (*ptr) [3];//pointer type is int (*) [3]
(5) int* (*ptr) [Type of 4];//pointer is int* (*) [4]
What do you think. The way to find out the type of pointers is simple.
The type that the pointer points to
When you access the memory area that the pointer points to by using the pointer, the type that the pointer points to determines what the compiler treats the contents of that memory area as.
Syntactically, you simply remove the pointer's name from the pointer declaration statement and the pointer to the left of the name, and the rest is the type that the pointer points to. For example:
(1) The type that the int*ptr;//pointer points to is int
(2) The type that the char*ptr;//pointer points to is Char
(3) The type that the int**ptr;//pointer points to is int*
(4) int (*ptr) [3];//pointer refers to the type int () [3]
(5) int* (*PTR) [The type pointed to by the 4];//pointer is int* () [4]
In the arithmetic operation of a pointer, the type that the pointer points to has a significant effect.
The type of the pointer (that is, the type of the pointer itself) and the type to which the pointer points are two concepts. As you become more and more familiar with C, you will find that the concept of "type", which is mixed with pointers, is divided into "type of pointer" and "type of pointer", which is one of the key points in mastering pointers. I read a lot of books, found that some poorly written books, the two concepts of the pointer stirred together, so look at the book to contradictions, the more the more confused.
The value of the pointer, or the memory area or address to which the pointer points
The value of a pointer is a numeric value stored by the pointer itself, which is treated as an address by the compiler, not as a generic value. In a 32-bit program, the value of all types of pointers is a 32-bit integer, because the memory address in the 32-bit program is all 32 bits long. The area of memory that the pointer points to is the memory area that begins with the memory address represented by the value of the pointer, and the length of the zeof (the type to which the pointer is pointing). Later, we say that the value of a pointer is XX, it is equivalent to say that the pointer to a piece of memory in the address of XX; we say a pointer to a block of memory is equivalent to saying that the value of the pointer is the first address of the area of memory.
The memory area pointed to by the pointer and the type pointed to by the pointer are two completely different concepts. In example one, the type that the pointer points to is already there, but because the pointer has not yet been initialized, the memory area it points to does not exist, or is meaningless.
After each encounter with a pointer, you should ask: What is the type of the pointer. What type the pointer refers to. Where the pointer is pointing.
Memory area occupied by the pointer itself
How much memory the pointer itself occupies. You just use the function sizeof (the type of the pointer) to find out. In a 32-bit platform, the pointer itself occupies a length of 4 bytes.
The concept of memory occupied by the pointer itself is useful in determining whether a pointer expression is a left value.
Arithmetic operations on pointers
The pointer can add or subtract an integer. The meaning of this operation of pointers is not the same as the addition and subtraction of the usual numerical values. For example:
Case TWO:
1, chara[20];
2, Int*ptr=a;
...
...
3, ptr++;
In the example above, the type of pointer ptr is int*, which points to an int, which is initialized to point to reshape variable a. In the next 3rd sentence, pointer ptr is added 1, which is handled by the compiler: it adds the value of the pointer ptr to sizeof (int), and in the 32-bit program, it is added to 4. Because the address is in bytes, the address that PTR points to is increased by 4 bytes from the address of the original variable A to the high address direction.
Since the length of the char type is a byte, the original PTR is four bytes beginning with the unit No. 0 of array A, which points to four bytes starting with unit 4th in array A.
We can iterate over an array with a pointer and a loop, and see examples:
Example three:
INTARRAY[20];
Int*ptr=array;
...
The code that assigns values to an integer array is omitted here.
...
for (i=0;i<20;i++)
{
(*ptr) + +;
ptr++;
}
This example adds the value of each cell in an integer array to 1. Because each loop adds pointer ptr 1, each loop accesses the next cell of the array.

Look again at the example:

Example four:

1, chara[20];
2, Int*ptr=a;
...
...
3, ptr+=5;
In this example, the PTR is added with 5, and the compiler does this by adding the value of the pointer ptr to 5 by sizeof (int), and the 32-bit program adds 5 times 4=20. Because the unit of the address is byte, the current PTR points to an address that moves 20 bytes to the high address direction than the address pointed to by the 5 ptr. In this example, the PTR before 5 points to the four bytes starting at Unit No. 0 of array A, plus 5, and PTR already points beyond the legitimate range of array A. Although this situation will be problematic in application, it is grammatically acceptable. This also shows the flexibility of the pointer.
If, in the example above, PTR is subtracted by 5, the process is much the same, except that the value of PTR is subtracted from 5 by sizeof (int), and the new PTR points to an address that moves 20 bytes to the lower address direction than the address pointed to by the original PTR.
To sum up, after a pointer ptrold plus an integer n, the result is that a new pointer ptrnew,ptrnew the same type as the Ptrold, and the type that the ptrnew points to is the same type as the Ptrold. The Ptrnew value increases the byte of n by sizeof (the type to which ptrold points) than the Ptrold value. That is, the memory area that the ptrnew points to will move the n by sizeof (the type that the Ptrold points to) to a higher address direction than the memory point that ptrold points to.
A pointer ptrold minus an integer n, the result is a new pointer ptrnew,ptrnew the same type as the Ptrold, and the type that the ptrnew points to is the same type as the Ptrold. The value of the ptrnew reduces the byte of n by sizeof (the type that the Ptrold points to) than the Ptrold value, that is, the memory area that the ptrnew points to will move the N times ptrold (the type that the sizeof points to) than the memory area to which the ptrold points to the lower address direction Bytes.
Operators & and *
Here & is to take the address operator, * is ... The book is called an "indirect operator".
The result of the &a operation is a pointer, the type of the pointer is the type of a *, the type of the pointer is the type of a, the address to which the pointer points, and that is the address of a.
The results of *p's operations are all the same. In short, the result of *p is what p points to, something that has these characteristics: its type is the type that P points to, and the address it occupies is the address that P points to.
Example five:
inta=12;
Intb
Int*p;
Int**ptr;
p=&a;
The result of the &a is a pointer, the type is int*, the type that points to is int, and the address that points to is the address of a.
*p=24;
The result of *p, where its type is int, the address it occupies is the address that P points to, and obviously *p is the variable A.
ptr=&p;
The result of the &p is a pointer, and the type of the pointer is the type of P plus a *, here is the int * *. The type that the pointer points to is the type of P, which is int*. The address that the pointer points to is the address of the pointer P itself.
*ptr=&b;
*ptr is a pointer, the result of the &b is also a pointer, and the type of the two pointers and the type is the same, so it is no problem to use &b to assign the *ptr value.
**ptr=34;
The result of the *ptr is the thing that PTR points to, here is a pointer, a second * operation on the pointer, and the result is a variable of type int.
Pointer expression
The final result of an expression if it is a pointer, then the expression is called a pointer table.
Here are some examples of pointer expressions:
Example SIX:
Inta,b;
INTARRAY[10];
INT*PA;
Pa=&a;//&a is a pointer expression.
INT**PTR=&AMP;PA;//&AMP;PA is also a pointer expression.
Both *ptr=&b;//*ptr and &b are pointer expressions.
Pa=array;
pa++;//This is also a pointer expression.
Example Seven:
CHAR*ARR[20];
char**parr=arr;//If you think of arr as a pointer, arr is also a pointer expression
CHAR*STR;
Str=*parr;//*parr is a pointer expression
str=* (parr+1);//* (parr+1) is a pointer expression
str=* (parr+2);//* (parr+2) is a pointer expression
Because the result of a pointer expression is a pointer, the pointer expression also has four elements that the pointer has: the type of the pointer, the type the pointer points to, the memory area the pointer points to, and the memory the pointer itself occupies.

Well, when a pointer expression's result pointer has explicitly had the memory occupied by the pointer itself, the pointer expression is a left value, otherwise it is not a left value.
In Example seven, &a is not a left value because it does not yet occupy a clear memory. *ptr is a left value, because *ptr this pointer has occupied the memory, in fact, *ptr is the pointer pa, since the PA has its own position in memory, then *ptr certainly have its own position.
The relationship between arrays and pointers
The array name of an array can actually be viewed as a pointer. Look at the following example:
Example eight:
Intarray[10]={0,1,2,3,4,5,6,7,8,9},value;
...
...
value=array[0];//can also be written as: Value=*array;
value=array[3];//can also be written as: value=* (array+3);
value=array[4];//can also be written as: value=* (array+4);
In the example above, the array name array, in general, represents the array itself, and the type is int[10], but if you think of an array as a pointer, it points to the No. 0 cell of the array, the type is int*, and the type that you point to is the type of the array cell-int. So it's not surprising that *array equals 0. Similarly, array+3 is a pointer to the 3rd cell of the array, so * (array+ 3) equals 3. Others, and so forth.

Example nine:
char*str[3]={
"Hello,thisisasample!",
"Hi,goodmorning.",
"Helloworld"
};
CHARS[80];
strcpy (s,str[0]);//may also be written as strcpy (S,*STR);
strcpy (s,str[1]);//may also be written as strcpy (s,* (str+1));
strcpy (s,str[2]);//may also be written as strcpy (s,* (str+2));
In the example above, STR is an array of three cells, each of which is a pointer to a string. Referring to the pointer array named STR as a pointer, it points to unit No. 0 of the array, its type is char**, and the type it points to is char*.
*STR is also a pointer, its type is char*, the type it points to is char, and the address it points to is the string "hello,thisisasample!" The address of the first character, that is, the address of ' H '. Str+1 is also a pointer to the 1th unit of the array, its type is char**, and the type it points to is char*.

* (str+1) is also a pointer, its type is char*, the type it points to is char, it points to "hi,goodmorning." The first character ' H ', and so on.

Here's a summary of the array name problem. Declares an array of typearray[n], the array name array has two meanings: first, it represents the entire array, its type is type[n], and second, it is a pointer, the type of the pointer is type*, and the pointer to the type, which is the type of the array cell, The memory area that the pointer points to is the array number No. 0 unit, which occupies a separate memory area, noting that it occupies a different memory area than the number No. 0 unit. The value of the pointer cannot be modified, that is, an expression similar to array++ is wrong.
Array name array can play different roles in different expressions.
In the expression sizeof (array), the array name array represents the array itself, so the sizeof function then measured the size of the entire array.
In the expression *array, the array acts as a pointer, so the result of this expression is the value of the array number No. 0. sizeof (*array) measured the size of the array cell.
Expression array+n (where n=0,1,2, .....) , the array acts as a pointer, so the result of the array+n is a pointer, its type is type*, and it points to the type, which points to the array nth unit. So sizeof (ARRAY+N) is measured by the size of the pointer type.
Example Ten
INTARRAY[10];
int (*ptr) [10];
Ptr=&array;:
In the example above, PTR is a pointer, its type is int (*) [10], the type he points to is int[10], and we initialize it with the first address of the entire array. In the statement Ptr=&array, the array represents the arrays themselves.

The function sizeof () is mentioned in this section, so let me ask, sizeof (pointer name) is measured by the size of the pointer itself or the type to which the pointer points. The answer is the former. For example:
int (*ptr) [10];
In the 32-bit program, there are:
sizeof (int (*) [10]) ==4
sizeof (INT[10]) ==40
sizeof (PTR) ==4
In fact, sizeof (objects) measure the size of the object itself, not the size of the other type.
Relationship of pointer and struct type
You can declare a pointer to a struct-type object.
Example 11:
Structmystruct
{
Inta
Intb
Intc
}
MYSTRUCTSS={20,30,40};
The structure object SS is declared, and the three members of the SS are initialized to 20,30 and 40.
mystruct*ptr=&ss;
A pointer to the structure object SS is declared. Its type is mystruct*, and the type it points to is mystruct.
Int*pstr= (int*) &ss;
A pointer to the structure object SS is declared. But its type is different from the type it points to and the PTR.
How can I access the three member variables of SS through pointer ptr.
Answer:
ptr->a;
ptr->b;
ptr->c;
And how to access the three member variables of SS through the pointer pstr.
Answer:
*pstr;//visited member a of the SS.
* (pstr+1);//access to member B of the SS.
* (PSTR+2)//access to the SS member C.
Although I've raised the above code in my msvc++6.0, it's not normal to use PSTR to access struct members, and to illustrate why it's not formal, let's see how we can access each cell of the array with pointers:
Example 12:
INTARRAY[3]={35,56,37};
Int*pa=array;
The method of accessing the three cells of array arrays via pointer PA is:
*pa;//visited unit No. 0,
* (PA+1)//access to Unit 1th
* (PA+2)//access to Unit 2nd

Top
Reply person:Yanglilibaobao ( ) () Prestige: 100 2007-1-12 9:56:03 Score: 0
?

The format is the same as that of an irregular method that accesses a struct member through a pointer.
When all of the C + + compilers arrange array cells, they always store each array unit in a contiguous storage area, and there is no gap between the unit and the unit. However, when you store individual members of a struct object, in some kind of compilation environment, it may be necessary to add a number of "padding bytes" between the adjacent two members, which might require a word alignment or two-word alignment or something, which could result in several bytes of space between the members.
Therefore, in example 12, even if *PSTR accesses the first member variable A of the structure object SS, it is not guaranteed that * (PSTR+1) will be able to access struct member B. Because there may be a number of padding bytes between member A and member B, maybe * (pstr+1) Just accesses these padding bytes. This also proves the flexibility of the pointer. If your goal is to see if there are any padding bytes between the members of the structure, hey, that's a good way to go.
The correct way to access a struct member over a pointer should be a method using pointer ptr in Example 12.
The relationship between pointers and functions
You can declare a pointer as a pointer to a function. INTFUN1 (Char*,int);
Int (*PFUN1) (char*,int);
PFUN1=FUN1;
....
....
Inta= (*PFUN1) ("ABCDEFG", 7);//Call function via function pointer.
You can use pointers as parameters for functions. In a function call statement, you can use a pointer expression as an argument.
Example 13:
Intfun (char*);
Inta
Charstr[]= "ABCDEFGHIJKLMN";
A=fun (str);
...
...
Intfun (char*s)
{
intnum=0;
for (inti=0;i{
num+=*s;s++;
}
Returnnum;
}
The function fun in this example counts the sum of the ASCII values of each character in a string. As I said before, the name of the array is also a pointer. In a function call, when you pass Str as an argument to the formal parameter s, you actually pass the value of STR to the address that s,s points to, but the STR and s each occupy their respective storage space. The addition of 1 to s in a function does not mean that STR is added to the 1 operation at the same time.
Pointer type conversions
When we initialize a pointer or assign a value to a pointer, the left side of the assignment number is a pointer, and the right side of the assignment number is a pointer expression. In the example we cited earlier, in most cases the type of the pointer and the type of the pointer expression are the same, and the type that the pointer points to is the same type as the pointer expression.
Example 14:
1, floatf=12.3;
2, float*fptr=&f;
3, Int*p;
In the example above, what should we do if we want the pointer p to point to the real number F? Is the following statement used?

p=&f;

Wrong. Because the type of the pointer p is int*, it points to a type of int. The result of an expression &f is a pointer, the type of the pointer is float*, and the type it points to is float. The two are inconsistent, the direct assignment method is not. At least on my msvc++6.0, the assignment statement of the pointer requires the type of the assignment number to be the same, and the type is the same, and I haven't tried it on the other compilers, so let's try it. In order to achieve our goal, you need to do "force type conversions":
p= (int*) &f;
If there is a pointer p, we need to change the type and point to Tyep*type, then the syntax format is:
(type*) p;
The result of this coercion type conversion is a new pointer, the type of which is type*, the type it points to, the address to which the original pointer points. All the attributes of the original pointer p have not been modified.
If a function uses a pointer as a formal parameter, a pointer type conversion will also occur during the combination of the argument and the formal parameter of the function call statement.
Example 15:
Voidfun (char*);
Inta=125,b;
Fun ((char*) &a);
...
...
Voidfun (char*s)
{
Charc;
c=* (s+3); * (s+3) =* (s+0); * (s+0) =c;
c=* (s+2); * (s+2) =* (s+1); * (s+1) =c;
}
}
Note that this is a 32-bit program, so the int type takes up four bytes and the char type is one byte. The function fun is to invert the order of four bytes of an integer. Have you noticed. In a function call statement, the result of the argument &a is a pointer, its type is int*, and the type it points to is int. The type of the parameter's pointer is char*, which points to a type that is char. In this way, in the combination of the argument and the formal parameter, we must do a conversion from the int* type to the char* type. With this example, we can imagine the compiler's conversion process: The compiler constructs a temporary pointer char*temp, then executes temp= (char*) &a, and finally passes the value of temp to S. So the final result is that the type of S is char*, the type it points to is char, and the address it points to is the first address of a.

As we already know, the value of a pointer is the address that the pointer points to, and in a 32-bit program, the value of the pointer is actually a 32-bit integer. Is it possible to assign an integer to the pointer directly as the value of the pointer? Just like the following statement:
Unsignedinta;
Type*ptr;//type are Int,char or struct types, and so on.
...
...
a=20345686;
ptr=20345686;//Our goal is to make pointer ptr point to address 20345686 (decimal

ptr=a;//Our aim is to make pointer ptr point to address 20345686 (decimal)
Compile it. It turns out that the following two statements are all wrong. Then our purpose cannot be achieved. No, there is another way:
Unsignedinta;
Type*ptr;//type are Int,char or struct types, and so on.
...
...
A= a certain number, this number must represent a valid address;
Ptr= (type*) a;//hehe, this is OK.
Strictly speaking (type*) and pointer type conversion (TYPE*) is not the same. The meaning of this (type*) is to treat the value of unsigned integer a as an address. The above emphasizes that the value of a must represent a valid address, otherwise, if you use PTR, there will be an illegal operation error.

Think about whether you can, in turn, take the address of the pointer to the value of the pointer as an integer. It's perfectly OK. The following example demonstrates taking a pointer's value as an integer and then assigning the integer as an address to a pointer:
Example 16:
Inta=123,b;
int*ptr=&a;
CHAR*STR;
b= (int) ptr;//takes the value of the pointer ptr as an integer.
Str= (char*) b;//assigns the value of this integer to pointer str as an address.
Now we know that you can take the value of a pointer as an integer, or you can assign an integer value to a pointer as an address.
Security issues with pointers
Look at the following example:
Example 17:
Chars= ' a ';
Int*ptr;
Ptr= (int*) &s;
*ptr=1298;
Pointer ptr is a pointer to a int* type that points to an int. The address it points to is the first address of S. In a 32-bit program, S takes up one byte, and the int type is four bytes. The last statement not only changes the byte of S, but also changes the three bytes in the high address direction of the S phase. What these three bytes are for. Only the compiler knows, and the person who writes the program is less likely to know. Perhaps these three bytes store very important data, perhaps these three bytes is just a code of the program, and due to your sloppy application of the pointer, the value of these three bytes has been changed. This can cause a crash error.
Let's look at one more example:
Example 18:
1, Chara;
2, int*ptr=&a;
...
...
3, ptr++;
4, *ptr=115;
This example is fully compiled and can be executed. But see No. In the 3rd sentence, after adding 1 to the pointer ptr, PTR points to a storage area in the high address direction adjacent to the shaping variable A. What's in this storage area. We don't know. It's possible that it's a very important piece of data, maybe even a code. And the 4th sentence actually writes a data to the storage area. This is a serious mistake. So when using pointers, the programmer must be very clear in mind: Where does my pointer point to. When you use pointers to access arrays, you should also be careful not to go beyond the low-end and high-end bounds of the array, or else it will cause a similar error.
In coercion type conversion of pointers: ptr1= (type*) ptr2, if sizeof (type of PTR2) is greater than sizeof (type of PTR1), it is safe to use pointer ptr1 to access the store that the ptr2 points to. If the sizeof (PTR2 type) is less than the sizeof (PTR1 type), it is not safe to use pointer ptr1 to access the store to which the ptr2 points. As for why, the reader combines example Shilai think about, should understand.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.