深入理解c语言的指针(A thorough understanding of the pointer to the C language)
深入理解c语言的指针(A thorough understanding of the pointer
to the C language)
A pointer is a special variable in which the stored values are interpreted as an address in memory. To find out a four pointer to pointer to the content: the type of the pointer, pointer types, the value of the pointer or pointer memory, and the pointer itself occupy memory area. Let us explain separately.
Declare a few pointers and put them in the example:
Example one:
(1) int*ptr;
(2) char*ptr;
(3) int**ptr;
(4) int (*ptr) [3];
(5) int* (*ptr) [4];
Pointer type
From a grammatical point of view, you simply remove the pointer from the pointer, and the rest is the type of the pointer. This is the type of pointer itself. Let's look at the types of pointers in the example:
(1) int*ptr; / / pointer type is int*
(2) char*ptr; / / pointer type is char*
(3) int**ptr; / / pointer type is int**
(4) int (*ptr) [3]; / / pointer type is int (*) [3]
(5) int* (*ptr) [4]; / / pointer type is int* (*) [4]
What about? Is it a simple way to find out the type of pointer?
The type to which the pointer points
When you pass the pointer to the memory area pointed to by the pointer, the type that the pointer points to determines what the compiler will look at as the content in that memory area.
Grammatically, you just have to declare the pointer in the pointer, the name and the name of the pointer on the left, and the statement left, and the rest is the type that the pointer points to. Such as:
(1) int*ptr; / / pointer type is int
(2) char*ptr; / / pointer type is char
(3) int**ptr; / / pointer type is int*
(4) int (*ptr) [3]; / / pointer type is int ([3])
(5) int* (*ptr) [4]; / / pointer type is int* ([4])
In arithmetic operations of pointers, the type to which the pointer points is of great use.
The type of pointer (the type of pointer itself) and the type pointed to by the pointer are two concepts. When you become more familiar with C, you will find that the pointer and mix together the "type" of this concept into "the type of the pointer and pointer type" two concepts, is one of the key points in the pointer. I read a lot of books, and found that some poor writing of the book, the hands of the two concepts together, so read the book before and after the contradiction, the more confused.
The value of a pointer, or the memory area or address pointed to by the pointer
The value of a pointer is the value that is stored in the pointer itself, and this value is treated by the compiler as an address, not a general value. In a 32 bit program, all types of pointers are values of a 32 bit integer because the memory address of the 32 bit program is all 32 bits long. The memory area that the pointer points to is a memory area starting at the memory address represented by the pointer value, Si zeof (the type indicated by the pointer). Later, we say that a value of the pointer is XX, it is equivalent to saying that the pointer to the address in XX led by a memory area; we say a pointer to a memory region, is equivalent to that the pointer value is the memory area of the first address.
The pointer to the memory area and the type to which the pointer points are two completely different concepts. In example 1, the
pointer pointing to the type already exists, but because the pointer has not yet been initialized, the memory area it refers to does not exist, or is meaningless.
Later, every time you encounter a pointer, you should ask: what is the type of this pointer? What is the type of pointer? Where does the pointer point?
The memory area occupied by the pointer itself
How much memory does the pointer itself occupy? You just use the function sizeof (pointer type) to test it. In the 32 bit platform, the pointer itself occupies 4 bytes in length.
The concept of the pointer itself occupy memory in the judgment of a pointer is very useful when the expression is an lvalue.
pointer arithmetic
A pointer can add or subtract an integer. The meaning of this operation of a pointer is different from the usual addition and subtraction of numerical values. Such as:
Example two:
1, chara[20];
2, int*ptr=a;
...
...
3, ptr++;
In this case, the type of the pointer PTR is int* type, it points to the int, it is initialized to the integer variable a. In the next third sentences, pointer PTR is added 1, so the compiler handles this: it adds sizeof (int) to the pointer PTR, and adds 4 to the 32 bit program. Since the address is in bytes, the address PTR refers to has increased by 4 bytes from the address of the original variable a to the higher address.
Since the length of the char type is one byte, the original PTR is the four byte starting at unit zeroth of the array a, pointing to the four byte from the start of unit fourth in the array a.
We can iterate over an array with a pointer and a loop, and look at the example:
Example three:
Intarray[20];
Int*ptr=array;
...
/ / omitting integer array assignment code.
...
For (i=0; I <20; i++)
{
(*ptr + +);
Ptr++;
}
This example adds 1 to the value of each unit in the integer array. Since each loop adds the pointer PTR to 1, each loop can access the next element of the array.
Look at the examples:
Example four:
1, chara[20];
2, int*ptr=a;
...
...
3, ptr+=5;
In this example, PTR is added 5, and the compiler does this: add the value of the pointer PTR to 5 multiply sizeof (int), and add the 5 multiply 4=20 in the 32 bit program. Since the
address unit is byte, the address indicated by the PTR now moves 20 bytes to the higher address direction than the address indicated by the PTR after 5. In this example, PTR, which is not added 5, points to the four byte at the beginning of the unit zeroth of the array a, and after 5, the PTR already points to the legal range of the array a. Although there are problems with the application, it is grammatically possible. This also reflects the flexibility of the pointer.
If the example above, PTR is minus 5, then the process is similar, but the value of PTR is minus 5 by sizeof (int), the new PTR will point to address more than the original PTR to address 20 bytes to low memory.
To sum up, a pointer ptrold adds an integer n, and the result is a new pointer ptrnew, the type of ptrnew is the same as the type of ptrold, and the type ptrnew refers to is the same type as the type ptrold points to. The value of ptrnew will be increased by ptrold by N, by sizeof (the type indicated by ptrold) bytes. That is, the memory area to which the ptrnew is pointing will move sizeof bytes of n (the type pointed to by ptrold) to the higher memory address than the memory area that the ptrold points to.
When a pointer ptrold subtracts an integer n, the result is a new pointer ptrnew, the type of ptrnew is the same as the type of ptrold, and the type ptrnew refers to is the same type as the type ptrold points to. The ptrnew value will be lower than the value of ptrold reduced by N sizeof (type ptrold point) bytes, that is to say, ptrnew refers to the memory area than ptrold to address memory area to low direction n by sizeof
(ptrold point) bytes.
Operators & & *
Here & take the address operator * =... The book is called the indirection operator".
The result of the operation of &a is a pointer. The type of pointer is the type of a plus a *, the type that the pointer points to is the type of a, the address that the pointer points to, and that is the address of the a.
The results of *p's calculations are multifarious. In short, the result of *p is what P points to; this object has these characteristics: its type is the type pointed by P, and the address it occupies is the address pointed to by P.
Example five:
Inta=12;
Intb;
Int*p;
Int**ptr;
P=&a;
The result of //&a is a pointer, the type is int*, the type pointing is int, and the address pointing is a.
*p=24;
The result of //*p, here, its type is int, and the address it takes is the address pointed to by P. Obviously, *p is the variable a.
Ptr=&p;
The result of //&p is a pointer, the type of the pointer is the type of P Plus a *, here is int * *. The type that the pointer points to is the type of P, and here is int*. The address to which the pointer points is the address of the pointer P itself.
*ptr=&b;
//*ptr is a pointer, and the result of &b is also a pointer, and the two pointers are the same type as the type they are pointing to, so it is no problem to assign *ptr to &b.
**ptr=34;
The result of the //*ptr is what the PTR points to, where it is a pointer, and then does a * operation on the pointer, and the result is a variable of the int type.
Pointer expression
The final result of an expression, if it is a pointer, is called the 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=&pa; //&pa is also a pointer expression.
*ptr=&b; //*ptr and &b are pointer expressions.
Pa=array;
This is pa++; / / pointer expressions.
Example seven:
Char*arr[20];
Char**parr=arr; / / if the ARR as if arr is a pointer, pointer
expressions
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 pointer expression is the result of a pointer, so the pointer expression also has four elements: the pointer is a pointer type, type pointer, the pointer to the memory area, the memory occupied by the pointer itself.
Well, when a pointer expression result pointer has clearly has its pointer memory occupied by the words, the pointer expression is an lvalue, otherwise it is not an lvalue.
In seven cases, &a is not an lvalue, because it has not occupied the clear memory. *ptr is an lvalue, because the *ptr pointer has occupied memory, *ptr is actually a pointer to PA, since PA is already in memory in their position, then *ptr of course has its own position.
The relation between array and pointer
The array name of an array can actually be considered 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 expressed as: value=* (array+3);
Value=array[4]; / / can also be expressed as: value=* (array+4);
In this example, general array name array represents the array itself, the type is int[10], but if array were a pointer, which points to an array of zeroth elements, the type is int* type, pointing to a type array unit is int. So it's not surprising that *array equals 0. Similarly, array+3 is a pointer to third units of an array, so * (array+3) equals 3.
Others and so on.
Example nine:
Char*str[3]={
"Hello, thisisasample."!",
"Hi, goodmorning.."",
"Helloworld.""
};
Chars[80];
Strcpy (s, str[0]); / / can also be written as strcpy (s, *str);
Strcpy (s, str[1]); / / can also be written as strcpy (s * (str+1));
Strcpy (s, str[2]); / / can also be written as strcpy (s * (str+2));
In this example, STR is an array with three elements, each element of the array is a pointer, the pointer pointing to a string. When the pointer array name STR is taken as a pointer, it points to the unit zeroth of the array, whose type is char**, and the type it points to is char*.
*str is also a pointer. Its type is char*, and the type it refers to is char. The address it refers to is the address of the first character of the string "Hello, thisisasample", that is, the address of `'H'. Str+1 is also a pointer to the unit first 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*, and the type it refers to is char, which points to the first character ''H', 'goodmorning.', 'Hi', and so on.
The following summarizes the array name of the array. Declare an array of TYPEarray[n], the array name array has two meanings: first, it represents the entire array, it is of type TYPE[n]; second, it is a pointer, the pointer type is TYPE* type, the pointer is TYPE, which is an array of type unit, the pointer
to the memory area is an array of unit zeroth, the pointer in possession of his own separate memory area, pay attention to it and the array unit zeroth occupy memory area is different. The value of this pointer cannot be modified, that is, expressions like array++ are wrong.
In different expressions, the array name array can play different roles.
In the expression sizeof (array), the array name array stands for the array itself, so the sizeof function measures the size of the entire array.
In the expression *array, array acts as a pointer, so the result of this expression is the value of the array, unit zeroth. Sizeof (*array) measures the size of the array cell.
Expression array+n (where n=0, 1, 2,...) In N, array acts as a pointer, so the result of array+n is a pointer, its type is TYPE*, and it points to the type "TYPE". It points to the cell of the array. So sizeof (array+n) measures the size of the pointer type.
In ten cases
Intarray[10];
Int (*ptr) [10];
Ptr=&array;:
In this example, PTR is a pointer, it is of type int (*) [10], he points to is int[10], we use the array to initialize its first address. In statement ptr=&array, array stands for the array itself.
In this section, the function sizeof () is mentioned, so let me ask sizeof (pointer name) to measure exactly the size of the pointer itself or the size of the type to which the pointer points The answer is the former. Such as:
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 any other size.
The relation between pointer and structure type
You can declare a pointer to a structure type object.
Example eleven:
StructMyStruct
{
Inta;
Intb;
Intc;
}
MyStructss={20,30,40};
The structure of the object SS / statement, and the initiation of the three SS members were 20, 30 and 40.
MyStruct*ptr=&ss;
/ / declare a pointer to a SS object pointer. Its type is MyStruct*, and the type it refers to is MyStruct.
Int*pstr= (int*) &ss;
/ / declare a pointer to a SS object pointer. But its type and the type it refers to is different from that of ptr.
How do I access the three member variables of SS through the pointer PTR?
Answer:
Ptr-> a;
Ptr-> b;
Ptr-> c;
Also, how do I access the three member variables of SS through the pointer PSTR?
Answer:
*pstr; / / SS a member access.
* (pstr+1); / / SS B member access.
* (pstr+2) / members visited the SS C.
Although I have the code in the MSVC++6.0 type raised me, but you know, it uses PSTR to access the structure members are not normal, in order to explain why not formal, let us see how each unit to access an array by pointer:
Example twelve:
Intarray[3]={35,56,37};
Int*pa=array;
The method to access the three units of the array array by pointer PA is:
*pa; / / visit No. zeroth unit
* (pa+1); / / visit No. first unit
* (pa+2); / / visit No. second unit
In format, it is the same format as the informal method of accessing structure members through pointers.
All C/C++ compilers always store individual array units in contiguous storage areas when arranging arrays of units, and there is no gap between the units and the units. But in each member holds the structure of objects, in a compiler environment, may require word alignment or double word aligned or what else need to add some "aligned padding bytes" between two adjacent members, which leads to the gap there may be several bytes between each member.
Thus, in example twelve, even if *pstr accesses the first member variable a of the structure object SS, there is no guarantee that the B (pstr+1) can access the structure member. Because the member a and the member B may have a number of padding bytes, pstr+1 might just have access to these padding bytes. This also demonstrates the flexibility of pointers. If your goal is to see if there are any padding bytes between the members of the structure, hey, that's a good idea.
The correct method of accessing a member of a structure by pointer should be the method of using pointer PTR in example twelve.
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 through a function pointer function.
Pointers can be used as function parameters. In function call statements, pointer expressions can be used as arguments.
Example thirteen:
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 code values of each character in a string. As mentioned earlier, the name of the array is also a pointer. In the function call, when the str is passed to the S parameter as an argument, is the actual value of STR transfer to s, s to address and STR to address, but STR and s occupy their respective storage space. Adding 1 to the s in the body of the function does not mean that the str is added 1 at the same time.
Pointer type conversion
When we initialize a pointer or assign a pointer, there is a pointer to the left of the assignment number, and to the right of the assignment number is a pointer expression. In our
previous examples, in most cases,
The type of the pointer is the same as the type of the pointer expression. The pointer points to the same type as the pointer expression.
Example fourteen:
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? Do you use the following statement?
P=&f;
Incorrect。 Because the type of pointer P is int*, the type it refers to is int. The result of the expression &f is a pointer. The type of pointer is float*, and the type it refers to is float. The two are inconsistent, the direct valuation method is not possible. At least on my MSVC++6.0, the assignment of pointers requires that both sides of the assignment number have the same type, and the type to which it is pointing is the same. Other compilers have not tried, and we can try. For our purposes, forced type conversions are required":
P= (int*) &f;
If there is a pointer to P, we need to change its type and the type it refers to to TYEP*TYPE, then the syntax format is:
(TYPE*) p;
The result of a forced type conversion is a new pointer, the type of the new pointer is TYPE*, and the type it refers to is TYPE, and the address it refers to is the address pointed to by the original pointer. All attributes of the original pointer P have not been modified.
If a pointer is used as a parameter, a pointer type conversion occurs in the combination of arguments and parameters of the function call statement.
Example fifteen:
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 takes one byte. The function fun is to invert the order of four bytes of an integer. Did you notice that? In the function call statement, the result of the argument &a is a pointer, whose type is int*, and the type it refers to is int. The pointer to the parameter type is char*, and the type it refers to is char. Thus, in the combination of arguments and parameters, we must perform a conversion from the int* type to the char* type. With this example, we can imagine the compiler doing the conversion process: the compiler first constructs a temporary pointer to 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*, and the type it refers to is char, and the address it refers to is the first address of A.
We already know that the pointer's value is the address to which the pointer points. In the 32 bit program, the pointer is actually a 32 bit integer. Is it possible to assign an integer as a pointer to a pointer? Just like the following statement:
Unsignedinta;
TYPE*ptr; //TYPE is int, char, or structure type, and so on.
...
...
A=20345686;
Ptr=20345686; / / our aim is to make PTR to 20345686 (decimal address pointer
)
Ptr=a; / / our aim is to make the pointer PTR points to 20345686 (decimal).
Compile it. It turned out that the last two statements were all wrong. So, can't we achieve our goal? No, there's still a way:
Unsignedinta;
TYPE*ptr; //TYPE is int, char, or structure type, and so on.
...
...
A= a number that must represent a valid address;
Ptr= (TYPE* a); / / Oh, it's ok.
Strictly speaking, the TYPE* here is different from the pointer type transformation (TYPE*). TYPE* means that the value of the unsigned integer a is treated as an address.
It 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 turn the pointer to the address, or the pointer, as an integer. Absolutely. The following example demonstrates taking the value of a pointer as an integer, and then assigning the integer as an address to a pointer:
Example sixteen:
Inta=123, b;
Int*ptr=&a;
Char*str;
B= (int) ptr; / / pointer to the value of PTR as an integer out.
Str= (char* b); / / the integer value as an address pointer is assigned to str.
Now that we know, you can take the pointer's value as an integer, or you can assign an integer value as an address to a pointer.
Pointer security
Look at the following example:
Example seventeen:
Chars='a';
Int*ptr;
Ptr= (int*) &s;
*ptr=1298;
The pointer "PTR" is a pointer to the int* type. The type it refers to is int. The address it refers to is the first address of S. In the 32 bit program, the s takes one byte, and the int type occupies four bytes. The last statement changes not only one byte of the s, but also the three byte of the high address direction that corresponds to the s. What are these three bytes for? Only the compiler knows, and the person who writes the program is unlikely to know. Maybe these three bytes store very important data. Maybe these three bytes are just one of the program's code, and the value of the three bytes has been changed because of your careless application of the pointer! This can lead to a crash error.
Let's look at another example:
Example eighteen:
1, chara;
2, int*ptr=&a;
...
...
3, ptr++;
4, *ptr=115;
The example can be compiled and executed entirely. But did you see that? In the third sentence, after adding 1 to the pointer PTR, the PTR points to a storage area in the direction of the high address adjacent to the shaping variable a. What's in this storage area? We don't know. It is possible that it is a very important data, and possibly even a code. And the fourth sentence actually writes a data to this storage area! This is a serious mistake. So, in using pointers, the programmer must be very clear in his mind: where exactly does my pointer point?. When accessing arrays with pointers, be careful not to go beyond the lower and upper bounds of the array, otherwise they can cause similar errors.
In the mandatory type conversion of the pointer: ptr1= (TYPE*) ptr2, if the sizeof (ptr2 type) is greater than sizeof (the type of PTR1), then it is safe to use the pointer PTR1 to access the storage area to which the ptr2 is pointing. If the sizeof (ptr2 type) is less than sizeof (the type of PTR1), it is not safe
to use the pointer PTR1 to access the storage area to which the
ptr2 is pointing. As for why, the reader, in conjunction with
example seventeen, think, and should understand.
本文档为【深入理解c语言的指针(A thorough understanding of the pointer to the C language)】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。