C programming 易 范 错 错 from the "Windows 95 Programming Guide", [US] Stephen R.davis has many errors that are easy for beginners (even experienced programmers) in C / C languages. An error that is informed will be free from it. Forgot to initialize the pointer This error is just a special form of general "forgetting initialization variables" (C / C variables do not initialize, while Basic). The reason why this error is worse is that its consequences are often worse: void somfunction () {int * pnvar int nval; nval = * pnvar; // bad enough. * Pnvar = nval; // Much Worse.} In this In the example, the pointer variable PNVAR never assigned. So you must assume that it is messy data from a chaotic information pointer, because the result is definitely messy data, write data to a chaotic information pointer, because it will lead to something you don't know. The data is rewritten. This is not harmful if it is rewritten. If the area being rewritten is useful, the data will be lost. This type of error is so hard to find because the problem will be presented until the program attempts to use the lost data. This problem may occur after the data is lost. Since this problem is difficult to judge, the Visual C compiler avoids its happening through some efforts. For example, a warning will be generated when you compiling the above functions. In this case, the compiler will tell you that the variable is not assigned before use. In many cases, it is impossible to tell you. Windows 95 operating system tries to help solve the problem with protecting memory to a certain extent: If the application is attempts to read or write from its memory, Windows usually intercepts the request and immediately terminates the program. Unfortunately, Windows 95 cannot intercept the invalid access of the memory owned by the application, and it cannot intercept all illegal access because some gaps must be retained to open with Windows 3.1's compatibility. Forgot to release the stack memory, remember that any memory that is assigned from the heap must be released. If you have used the memory, forget to release it, the system memory will become more and more, until your program can't run and crash. This problem will appear in some of the following situations: car * getanewcar (int NoccuPants) {car * pcar; if (NoccuPants <4) {pcar = new car (2); // Get a two-door.} Else { PCAR = New Car (4); // OtherWise, A Four-door.} Return Pcar;} Void Gotothestore (int NocuPants) {// Get a car. Car * pcar = getanewcar (noccupants); // Now drive. In this case,}} In this case, the function GotoStore () first assigns a new car to open - this is a bit waste, but you will definitely agree that this algorithm can work. As long as the new car is assigned, it will open the store with the call to PCAR-> Drive (Store). The problem is that after it is safe to reach the destination, the function does not destroy the Car object. It just simply exits, so that the memory is lost.
Typically, when the object PCAR has a scope in the program, the programmer should rely on the destructor ~ Car release memory. But here can't do it, because the type of PCAR is not Car *, the destructor does not call the destructor when the PCAR has a scope. The corrected function is as follows: void gotothestore (int NocuPants) {// Get a car. Car * pcar = getanewcar (noccupants); // Now drive. IF (PCAR) {PCAR-> Drive (store);} // now delete the object, return the memory. Delete pcar;} You should use the DELETE operator to delete it, this must be kept in mind. Returns another common and memory related issue for local memory is the address of the local memory object from the function. When the function returns, the object is no longer valid. This memory address may be used by this new function when a function is called next time. Continue to use this memory pointer to write a local memory of the new function. This common problem appears in this way: Car * getanewcar (int NoccuPants) {car * pcar; if (NoccuPants <4) {Pcar = & car (2); // Get a two-door.} Else {PCAR = & car 4); // OtherWise, a four-door.} Return PCAR;} Please note how the pointer PCAR is assigned to the local address of the unnamed object established by the constructor car (). There is no problem so far. However, once the function returns this address, the problem is generated because the temporary object at closed braces will be destructed. Make the operator confusing C inherited a set of comparison with a confusing operator from its senior C. Adding the flexibility of grammar rules, it is easy to make confused programmers to make programmers to use errors. The most famous example of this situation is as follows: IF (nval = 0) {// do sometying if nval is nonzero.} The programmer obviously wants to write if (nval == 0). Unfortunately, the above statement is completely legal, although there is no meaning, the C statement assigns NVAL to 0, and then checks whether it is non-zero (this is impossible). The result is that the code in the braces will never be executed. Other pairs of easy mistakes are & and &&, and / and //. 0 Four faces according to the use of it, constant 0 has four possible meanings: ☆ Integer 0 ☆ Cannot be the address of the object address ☆ Logic FALSE ☆ String Terminal I can prove that these meaning is very different. Actual. For example, the following assignments are legal: int * pint; pint = 0; // this is leagal. The following assignment is illegal: int * pint; pint = 1; // this is not. The first assignment is legal Because of the second definition in the table: constant 0 can be an address, but constant 1 is not.
This meaning of multi-performance results in an incorrect error: // copy a string from psource to ptarget - incorrect version. While (psource) {* ptarget = * psource ;} In this case, the While cycle attempts to point by PSource The source string is copied to the memory block pointed to by the PTARGET. But unfortunately, the condition is wrong, it should write this: // copy a string from psource to ptarget - incorrect version. While (* psource) {* ptarget = * psource ;} You can see, when When the character pointing by PSource is NULL, the termination condition appears. This is the fourth definition of 0. However, the code written here is to view the address PSource whether it is zero, which is the second definition. The final result is that the while () loop continues to write to the program to crash. There may also be confusion between the other definitions of 0. The only solution is to be careful when you use constant 0. The declaration of the declaration is very confusing, but C -maintains the reverse compatibility with C - but also have a contradiction between some statements, you must avoid this contradiction. Class myclass {public: myclass (int NARG1 = 0, int NARG2 = 0);}; MyClass MCA (1, 2); MyClass MCB (1); MyClass MCC (); MCA is an object constituted by parameters 1 and 2, and The MCB is an object constituted by parameters 1 and 0. So you may think that MCC is an object constituted by parameters 0 and 0, however, the case is not the case. MCC () is a function that does not have parameters, which returns to the object of class myclass with numerical values. Another confusion is generated by the initialization operator =: MyClass MCB = Na; // Same As MyClass MCB (NA) In order to enhance compatibility with C, allow this to use =; however, you should avoid this structure because it is not Consistent applicable. For example, the following programs will not have expected results: MyClass MCA = NA, NB; this illustrates an object MCA (NA), which has an independent object NB using the default constructor, instead of illustrating an object MCA (NA) , Nb). Stick to use C format - this is the safest. Calculate the order of chaos of C and C operators, so that you can know how to calculate how expression: A = B * C D; however, the order does not affect the calculation order of the child expression. Let us change the example of the example in a way that looks not important: a = b () * c () d (); now the problem is, what kind of order call function B () in this expression, C () and d ()? The answer is that the order is completely uncertain. Worse, the order cannot be determined by the use of parentheses. So the following expression does not work: a = (b () * c ()) D (); function calculation order is usually not worth careful. However, if these functions have side effects, in some way, it is important that the order is important.
For example, if these functions change the same global variable, the result is different, depending on the order in which functions are called. Even when the function is not involved, the mutual side effects will also affect: int Ni = 0; cout << "Na [0] =" << Na [Ni ] << "Na [1] =" << Na [Ni ] << "/ n"; this expression problem is that a single expression contains two sub-expressions-variable NIs with mutually side effects. Which Na [Ni ] is first executed, the NA [NI ] or the left Na [Ni ] is not a way to say that the above code may work in an expected manner, but may not. Note The Virtual Member Function In order to overload the virtual member function in the subclass, you must use the parameters and return types of the function in the subclass as the function as the function in the base class. This is not always clear. For example, the following codes seem to speak: class base {public: Virtual void AFUNC (Base * Pb);}; class subclass: public base {public: Virtual void AFUNC (Subclass * ps);}; This code will compile, But there is no later connection. The parameters of the function base :: Afunc () are Base * type, and the function Subclass :: Afunc () is subclass *, which are different. The only exception to this rule is the following example, which conforms to ANSI C standard: class base {public: Virtual void base * Afunc ();}; class subclass: public base {public: virtual void subclass * Afunc ();}; In this case, each function returns the address of its inherent type object. This technology is very common, so the Standard Commission decided to recognize it. Calling the virtual member function from the constructor is called the virtual function from the constructor as the previous connection, so that it has shorted those originally simple ability: class base {public: base (); virtual void buildsection () (); In this case, the programmer wants that the constructor wants that the constructor wants the constructor to construct the constructor. Call buildsection (), call Base :: buildsection () when the object is being constructed is a base object, call Subclass :: buildsection () when the object is a class subclass object (). This example does not work because of the following simple reasons: When the buildsection () is completed, the object being constructed is just an BASE object. Even if the object ends a subclass object, you have to wait until the Subclass constructor has passed it over again. In these cases call subclass :: buildsection () may be fatal.