Iv. array and pointer
The C language provides two methods to access Arrays: pointer arithmetic and array subscript.
The speed of pointer arithmetic can be higher than that of array subscript. Given the speed, programmers generally use pointers to access array elements.
1. array: an ordered set of data of the same type, which is identified by a unique name.
1. the array must be declared directly. The Compiler allocates memory space for it during compilation.
2. In c89, the array must be fixed and the array size is fixed during compilation. c99 allows variable-length arrays (VLA), and the array size is determined at runtime. However, only the local array can be applied for variable length. The variable length array is added to support numerical processing.
[Example] void F (INT longeur, int wide) {int matrix [longeur] [wide]; /* define a matrix * // * the length of the array is determined by two parameters */}
3. All elements of the array occupy continuous memory space, which is linearly stored in the memory. The memory space required to save the array is directly related to the base type and array length. Memory space occupied by arrays = sizeof (base type) * array length.
4. C does not check whether the array is out of bounds. The program can cross the border on both sides. Programmers should join the cross-border inspection by themselves. Arrays can be used out of bounds, but cannot be used during initialization!
5. Pass the array to the function: There are three methods to define the array parameters: pointer, fixed length array, no size array. Void func1 (int * ){}
Void func2 (int A [10]) {}
Void func3 (int A []) {}
In the Declaration of function parameters, the array size does not matter because the C language does not have a boundary check. In fact, after the second method is compiled, the code generated by the compiler is to let the function accept pointers without generating an array of 10 elements.
(1) arrays in the form parameters cannot be understood as arrays, but must be understood as pointers: sizeof () cannot be used to evaluate the size, but can be assigned a value, this is different from the pointer constant of the array name. When passing values, content is copied, but there may be many elements in the array. To avoid copying a large amount of content and occupying too much memory, C requires that passing parameters in the array is a pointer.
(2) int A [] [] cannot be used as a form parameter, because a is an array pointer to a data type such as int [], but the subscript size is not determined. Int A [] [8] can be used, and the two-dimensional array name (no need to display the conversion) can be used as the actual parameter.
6. When processing an array element, using the auto-increment pointer (P ++) method is usually faster than directly using the array subscript, and using the pointer can optimize the program.
7. c Allows defining multi-dimensional arrays. the maximum number of dimensions is defined by the compiler. However, arrays larger than three dimensions are not commonly used because the memory space required for multi-dimensional arrays increases exponentially. In addition, calculating the dimension subscript takes up the CPU time (the speed of accessing multi-dimensional array elements is slower than that of accessing one-dimensional array elements ).
8. During array initialization, note that c89 requires constant initialization characters, while c99 allows constant initialization characters to initialize local arrays.
2. String: The most common place for arrays (especially one-dimensional arrays.
1. C does not have special string variables, and all its operations are implemented by a one-dimensional array. A string is a special form of character arrays. The only difference is that it acts as a whole operation, while a Normal Array cannot. The final difference lies in null (0) at the end.
2. Note the difference between string type and string type in C ++ (providing the OO method for string processing). C does not support it.
3. Initialization operation: place a String constant in the const zone (Data zone, global variable zone, and static variable zone) of the data zone ), when initializing a character array with a String constant, there is an operation to copy the content, instead of simply pointing to it with a pointer. In fact, the question of whether a String constant is in the constant zone or heap zone, What storage structure is used, and whether it is continuous depends on different compilers.
4. String input and output: The following functions are defined by <stdio. h>.
(1) printf ("% s", STR );
(2) puts (STR );
(3) scanf ("% s", STR );
(4) gets (STR );
5. String operation: The following functions are defined by <string. h>.
Strcpy (S1, S2), strcat (S1, S2), strlen (STR), strcmp (S1, S2), strchr (S1, CH), strstr (S1, S2 ).
[Note] the = comparison between character arrays and character pointers is an address comparison, and the result cannot be true. But the = comparison of the String constant is not necessarily: VC is overloaded with =, and the address comparison of the String constant is changed to content comparison (as if the output character pointer is actually an output string, is overloaded), SO ("ABC" = "ABC") is established in VC, but not in BC. To avoid ambiguity, use strcmp () as much as possible.
3. pointer ):
Pointers are the essence of the C language. Correct Understanding and flexible use of pointers are the criteria for measuring the successful compilation of C Programs.
1. advantages of using pointers:
--> The ability to flexibly modify the value of the real variable for calling a function.
--> Supports dynamic memory allocation to facilitate dynamic data structures (such as two * trees and linked lists ).
--> It can improve the efficiency of some programs.
--> Implements buffer-based file access.
2. the pointer is the address. Technically, any type of pointer can point to any location in the memory. However, pointer operations are all type-based.
Pointer operations are executed relative to the pointer's base type. Although technically pointers can point to other types of objects, pointers always point to objects of its base type. Pointer operations are governed by the pointer type rather than the object type it points.
3. pointer expression: in principle, Expressions Involving pointers comply with the rules of other C expressions.
(1) printf ("% P ",...); /* Display the address in the format used by the host computer */
(2) pointer conversion:
--> Void * type: Generic pointer. Generally, pointers with unknown basic types are used. It allows the function to specify a parameter. This parameter can accept pointer variables of any type without reporting Type mismatch. When the memory semantics is not clear, it is also commonly used to refer to the original memory.
[Example] A function can return "multiple" types (similar to malloc (): void * F1 (void * P) {return P;} void main (void) {int A = 100; int * PP = & A; printf ("% d/N", * (int *) F1 (PP )));}
--> For pointer conversion of other types, explicit forced type conversion must be used. However, it is important to note that an ambiguous behavior may occur when a pointer of one type is converted to another type.
--> Int type can be converted to a pointer or a pointer to an int type. However, forced type conversion must be used and the conversion result is a defined implementation, which may lead to non-defined behavior. (Forced conversion is not required when converting 0 because it is a null pointer)
--> In order to be better compatible with C ++, many c programmers discard pointer conversion because mandatory type conversion, including void *, must be used in C ++.
(3) pointer arithmetic: only addition and subtraction operations can be performed on the pointer. --> Add and subtract pointer and integer. --> Subtract another pointer from a pointer (mainly to evaluate the pointer offset ).
(4) pointer comparison: it is mainly used when two or more pointers point to a common object.
4. Initialization pointer:
(1) The value of a non-static local pointer is unknown before it is declared but not assigned a value.
(2) The global and static local pointers are automatically initialized to null.
(3) using a pointer before assigning a value may not only paralyze the program, but also cause the OS to crash. The error is serious!
(4) [Regular usage] assign null to a pointer that does not currently point to a valid memory space. Because c ensures that the null address does not have an object, any NULL pointer means that it does not point to any object and should not be used. The NULL pointer is used to indicate that the unused pointer is basically the Protocol followed by the programmer (but not the mandatory rule of C ).
[Example] int * P = NULL; * p = 1;/* error! * // * The program can be compiled, But assigning a value to 0 usually causes the program to crash */
5. function pointer: void process (char * a, char * B, INT (* APPEL) (const char *, const char *)); /* the function is called by pointer, and Appel is a function pointer */
In work, you often need to input arbitrary functions into the process. Sometimes you need to use an array composed of function pointers. For example, when interpreting a program running, you often need to call various functions according to the statement. In this case, it is very convenient to replace the large switch statement with an array composed of function pointers, which is called by the array subscript.
6. Dynamic Allocation (Dynamic Allocation) memory space: the memory space obtained by the program during running.
Global variables are allocated memory space during compilation. Non-static local variables use the stack zone. Both use fixed-length memory space during runtime.
(1) to implement a dynamic data structure, the C dynamic allocation function allocates memory space in the heap area. Heap is the free memory zone of the system, and the space is usually large.
(2) core functions: malloc () and free ().
(3) The heap area is limited. After memory space is allocated, you must check the return value of malloc () to ensure that it is not empty before the pointer is used.
(4) Never use an invalid pointer to call free (). Otherwise, the free table will be damaged.
7. Miscellaneous: Common pointer-related problems.
(1) In some cases, it is important to use const to restrict pointers to improve program security. You can take a closer look at the system functions compiled by Microsoft.
(2) It is difficult to locate pointer errors because the pointer itself is normal. The problem is that when incorrect pointer operations are performed, the most difficult troubleshooting error may be introduced: The program performs read or write operations on unknown memory areas.
--> Read: The worst case is getting useless data. --> Write: Other code or data may be washed away.
This kind of error may occur after the program has been executed for quite a while, so the troubleshooting work may go astray.
Although using pointers may cause strange errors, we cannot discard using pointers. (I remember when I started my project, I used more than 200 arrays in my first project due to fear of pointers ......) Exercise caution when using pointers. Remember to first determine where the Pointer Points to the memory.
[Example 1] uninitialized pointer ). Int * P; scanf ("% d", P);/* Error * // * write the value to an unknown memory space */
When you run a applet, the random address in P points to the security zone (not to the code and data of the program, or OS. However, as the program grows, the probability that P points to an important area increases, and the program is paralyzed.
[Example 2] incorrect assumptions about data placement in memory. Char A1 [80], A2 [80]; char * P1 = A1, * P2 = a2; If (P1 <P2) {/* handle */}/* conceptual error! */
Generally, programmers cannot ensure that the data is in the same location in the memory. They cannot ensure that the data is stored in the same format on various platforms, or that the methods for various compilers to process the data are the same. When comparing pointers to different objects, it is easy to produce unexpected results.
[Example 3] we assume that the adjacent arrays are arranged in order to simply add value to the pointer and hope to span the array boundary. Int A1 [10], A2 [10]; int * P = A1; For (INT I = 0; I <20; I ++) * P ++ = I; /* Error */
Although it can be applied to some compilers under some conditions, it is assumed that the two arrays first store A1 in the memory and then store A2. This is not often the case.
[Example 4] always focus on the current position of the pointer. Char A [80], * P; P = A;/* Error */do {/* P = A; put this sentence in a circular body */gets (); /* read */while (* P) printf ("% d", * P ++);} while (strcmp (a, "done "));
In the first loop, P starts from a [0. In the second loop, the P value starts from the end point of the first loop. In this case, P may point to another string, another variable, or even a certain segment of the program.
[Example 5] address of the expression. Int * P = & (a + B);/* Error */
In C, & can only get the address of one variable. In a program, the storage space of other expressions except variables is not accessible.
4. pointers and arrays:
Arrays are closely related to pointers, almost like UNIX and C: they are independent of each other. In fact, the name of a one-dimensional array can be regarded as a pointer constant without limitation: it can perform pointer operations, assign values and reference values according to address units, and can also be used to initialize the same type of pointer variable; however, you cannot assign values to the names of One-dimensional arrays.
Char P [] = "Hello, world! "; Char * P =" Hello, wrold! ";/* The two statements are completely equivalent */
1. pointer array: usually used to place pointers to strings.
In the program, string operations are very common, but the introduced technology still has some limitations. In addition, in some special projects, several strings may need to be passed as parameters to the function, but the length of the string cannot be determined. This is obviously not suitable to use a fixed length array.
[Example 1] an error message is output after an error number is specified. Void print_error (int n) {static char * erreur [] = {"syntax error/N", "Variable Error/N", "disk error/N "}; printf ("% s", error [N]);}
[Example 2] Typical application: Print command line parameters (similar to echo commands ). Void main (INT argc, char ** argv, char ** env) {While (* ++ argv) printf ("% s", * argv );}
[Example 3] access the characters in the command line parameters (apply the second subscript to argv ). Void main (INT argc, char * argv [], char ** env) {int I, j; for (I = 0; I <argc; ++ I) {J = 0; while (argv [I] [J]) {putchar (argv [I] [J]); j ++ ;} printf ("/N ");}}
[Note] --> do not assign values by subscript as an array, or use indirect references such as * (p + n) to modify the value of a unit, this may cause running errors because the String constant is in the constant area and cannot be modified. Strictly speaking, it is wrong to point a normal pointer to a constant, and a compilation error of "cannot convert from 'const type * 'to 'Type *'" will be generated. Character pointer Initialization is a special case. A character pointer variable can point to a String constant, but its content cannot be modified. Convert const char * To char * to obtain the correct address, which can be referenced but cannot be modified. (If you convert a const int * To an int *, you cannot obtain the correct address. This is a special character of a String constant ).
--> It is sometimes feasible to read the content of a unit by subscripts or indirect references such as * (p + n), depending on how different compilers store string constants: in the constant or heap area, the storage structure used, and whether the block chain is continuous ). It is always feasible to reference and assign values to character arrays because it opens up a continuous space and copies the content.
2. For arrays A [], the values of Output A, * a, and & A are the same, but we cannot consider them to have the same meaning. A has a double meaning, but through printf (), the first element address is displayed. * In A, A obtains the meaning of its array pointer, and the value is the address of the first element; & A takes the meaning of its custom data type, and its value is the address of the first element in the structure. If a is assigned to the array pointer Variable P, & P is the P address, because P does not have the custom data type meaning of the array. When the array name is used to initialize the pointer or array pointer, automatic type conversion is performed, taking its pointer meaning.
That is to say, do not take the value assignment as the same. After learning C ++ in the future, I will have a deeper understanding. C ++'s operator overloading and automatic type conversion imply many things.
3. Pure pointer array: The method for defining arrays in Java. Such an array is a real multi-level pointer. It cannot use sizeof () to calculate the size of an array, but it can realize multi-dimensional dynamics and has a high access efficiency (No multiplication is required to address it ). [Example] int N1, N2, N3;
Int * P1 = new int [N1]; // P1 [N1], but unlike normal array names, P1 is not a pointer constant, but a memory pointer variable.
Int ** P2 = new int * [N1]; for (INT I = 0; I <N2; I ++) P2 [I] = new int [n2];
Int *** P3 = new int *** [N1]; for (Int J = 0; j <N1; j ++) {P3 [J] = new int * [n2]; for (int K = 0; k <N2; k ++) p2 [J] [k] = new int [N3]; // three-dimensional dynamic array P3 [N1] [n2] [N3]} P2-
4. pointer (pointers to pointers): the pointer array name is a second-level pointer. In practice, pointer pointing to a pointer is rarely needed, which may lead to Conceptual errors.
5. dynamically allocated array (dynamically allocated array ):
[Example 1] char * P = (char *) malloc (80);/* the following test must be performed on P to avoid using a null pointer */If (! P) {printf ("error/N"); exit (1 );}
Get (p); For (INT I = strlen (P)-1; I> = 0; I --) putchar (P [I]); free (P );
[Example 2] int (* P) [10] = (INT (*) [10]) malloc (40 * sizeof (INT )); /* to be compatible with C ++, all pointer conversions must be discarded */If (! P) {printf ("error/N"); exit (1 );}