Document directory
- 1 Symbol
- 2 value assignment
- 3 greedy method in lexical analysis
- Octal
- 5 Characters and string
- 6 nested comments
- 7. Understand the function declaration
- 8 operator priority
- 9 pointer and array
- 10. array declaration as a parameter
- 11. Boundary computing and asymmetric Boundary
- 12 main return value
- 13 Connector
- 14 declaration and definition
- 15 File Access
- 16 buffer output and Memory Allocation
- 17 use errno to detect errors
- 18 signal Functions
- 19 pre-processor
1 Symbol
The term "symbol" refers to a basic component unit of a program. Its function is equivalent to a word in a sentence. The part in the compiler that is responsible for breaking down the program into one symbol, which is generally called the "lexical analyzer ".
2 value assignment
In general, the value assignment operation is relative to the comparison operation.Appear more frequently, SoFewer characters= Is given a more common meaning ------ value assignment operation.
3 greedy method in lexical analysis
How Should expression a --- B be understood?
Greedy method in lexical analysis: each symbol should contain as many characters as possible. "If the (compiler) input stream has been decomposed into symbols before a character, the next symbol will includeThe longest string that may constitute a symbol." Understanding this rule makes it easy to understand the above expression. Equivalent
A ---B
Octal
If an integer constant'sThe first character is a number.0, The constant will be treatedOctal.
5 Characters and string
A character enclosed in single quotes actually representsAn integerThe integer corresponds to the Sequence Value of the character in the character set used by the compiler. A string caused by double quotation marks represents a pointPointer to the starting character of an unknown ArrayThe array is initialized by characters between double quotation marks and an extra zero binary character '\ 0.
6 nested comments
# If 0
/*
...
...
*/
//
# Endif
7. Understand the function declaration
(* (Void (*) () 0) (); ---- the hardware calls a subroutine whose first address is 0.
Seeing such an expression, Every programmer may feel "chilling ".
There is actually only one simple rule to construct an expression: declare it according to the method used.
How can we understand this sentence?
Float f, g;
The meaning of this statement is: when the expression f and g are evaluated, they are of the floating point type.
Float ff ();
The meaning of this statement is: The expression ff () returns a floating point number, that is, ff is a function that returns a floating point type.
Float * pf;
This statement indicates that * pf is a floating point number, that is, pf is a pointer to a floating point number.
Float * g (), (* h )()
Declared such a function g: the return value is a pointer to a floating point, the parameter list is empty.
Declared h is a pointer pointing to such a function-return value float, the parameter list is null.
Float fun ()
{
}
H = fun; // value assignment
H (); // call the function fun-this is a short form
(* H) (); // call the function fun-this is the standard form
Once we know how to declare a variable of a given type, the type conversion operator of this type is easy to get:You only need to remove the variable name and semicolon at the end of the declaration from the Declaration, and then encapsulate the remaining parts with a bracket.. For example, because of the following statement:
Float (* h )();
Indicates that h is a pointer to a function with a return value of the floating point type. Therefore,
(Float (*) () // note that there is an asterisk *
It is a type conversion character that refers to a pointer to a function with a return value of the floating point type.
In the preceding example, you can use this type conversion character as follows:
Void * p = fun;
(Float (*) () p) (); // call fun
(* (Void (*) () 0) (); ---- the hardware calls a subroutine whose first address is 0.
This expression indicates that the child routine whose first address is 0 is called. The prototype of the Child routine is the void function, and its parameter list is empty.
With typedef, this problem is much clearer.
Typedef void (* funcptr )();
(* (Funcptr) 0) (); // equivalent to (* (void (*) () 0 )();
8 operator priority
It is best to use parentheses if you are not sure.
9 pointer and array
The C language only contains one-dimensional arrays, And the array size must be determined as a constant during compilation. However, array elements can be of any type (so multi-dimensional arrays can be defined ).
For an array, we can only do two things: determine the size of the array and obtain the pointer to the element with the subscript 0 of the array. The computation with the array subscript is actually performed through the pointer.
Int calendar [12] [31];
If the calendar is not used for sizeof operations, and the other is used for other purposes, the calendar is always converted into a pointer to the starting element of the calendar ar array.
The pointer type is very important. The plus or minus operation is defined according to its type. A void pointer cannot be added or subtracted because it does not know the size of the element it points.
Int a [5] [3] = {1, 2, 3,
4, 5, 6,
6, 7, 8,
9, 10, 11,
12, 13, 14 };
A is the address of a one-dimensional array with five elements. Each element contains three int integers.
Printf ("% d \ n", ** (a + 3) Print Output 9
Sizeof (a [1]) = 12
Sizeof (* (a + 1) = 12;
* (A + 1) points to the address of the second element of the array, which is a one-dimensional array containing three int integers.
Int (* ap) [31]; // pointer to an array
Int * p [10]; // pointer Array
10. array declaration as a parameter
Int strlen (char s []) is equivalent to int strlen (char * s ).
It should be noted that if a pointer parameter does not actually represent an array, even if it is technically correct, the array-based recording method will often be misleading.
Main (int argc, char * argv []) is equivalent to main (int argc, char ** argv, the previous statement emphasizes that argv is a pointer to the starting element of an array. The element of this array is of the character pointer type. Because these two statements are equivalent, we can choose one that best reflects our intent.
11. Boundary computing and asymmetric Boundary
Int I, a [10];
For (I = 0; I <= 10; I ++)
A [I] = 0;
If the compiler used to compile this program allocates memory to the variable by decreasing the memory address, the program will be in an endless loop. Because a [10] = 0 is equivalent to I = 0, so when I increments to 10, it returns to 0, and the loop continues.
In some languages, the array subscript starts from 1, and in C languages, the array subscript starts from 0. The upper bound of this array (that is, the first "out-of-bounds point") is the number of array elements!
Two general principles to avoid "railing errors" (errors that often occur during border computing:
1. Consider the instance in the simplest case and then deduce the result.
2. Calculate the boundary carefully.
Write a function: The buffwrite function has two parameters. The first parameter is a pointer pointing to the first character to be written into the buffer. The second parameter is an integer, number of characters to be written into the buffer. Suppose we can call the flushbuffer function to write the content in the buffer, and the flushbuffer function will reset the pointer bufptr to point it to the starting position of the buffer.
In the following two examples, we should be careful with the "railing error ".
Version 1
Void bufwrite (char * p, int n)
{
While (-- n> = 0)
{
If (bufptr ==& buffer [N])
Flushbuffer ();
* Bufptr ++ = * p ++;
}
}
Optimized version 2
12 main return value
A typical solution is that if the return value is 0, the program is successfully executed. If the return value is not 0, the program fails to be executed. If the main function of a program does not return any value, the execution may fail. Therefore, the robust way is to always show that the correct value is returned.
13 Connector
Connector: does not understand the C language, but can understand the machine language and memory layout.
A typical connector integrates several target modules generated by the compiler or assembler into an entity called a load module or executable file that can be directly executed by the operating system.
Compiler: translate the C source program into a form that the connector can understand.
Simple compilation flowchart:
14 declaration and definition
Sometimes declarations are also definitions.
A declaration is a definition, unless declared: introducing name definition: introducing entity.
Extern int
Extern indicates that the storage space of a is allocated elsewhere in the program.
Each external object must be defined somewhere.
Static int
Static modifier is a useful tool to reduce name conflicts. In the above definition, the scope of a is limited to a single file.
Ensure that the same object has only one type (uniform definition and Declaration), and ensure that it is defined only in one place.
15 File Access
In C, you must insert a call to the fseek function into the file to perform both input and output operations.
16 buffer output and Memory Allocation
Set output buffer
Setbuf (stdout, buf)
Call fflush to refresh the buffer
After the buffer is set, the data is buffered before it is output only when the buffer is full.
The buffer size is defined by the bufsiz in the system header file <stdio. h>.
17 use errno to detect errors
Check errno again after an error is confirmed. Instead of checking errno to determine whether an error has occurred.
18 signal Functions
Make the signal processing function as simple as possible. For example, do not use malloc in the signal handler.
19 pre-processor
All macro definitions are replaced in the preprocessing phase.
We 'd better enclose every parameter in the macro definition in parentheses. Similarly, the entire result expression should be enclosed in parentheses to prevent problems that may occur when the macro is used in a larger expression.