Http://learn.akae.cn/media/ch10s03.html3. Observation Point
Next we will know the steps in the previous section after debugging, althoughSum
The initial value 0 has been assigned, butWhile (1)
Add at the beginning of the loopSum = 0;
:
Example 10.3. debug an instance at the observation point
# Include <stdio. h> int main (void) {int sum = 0, I = 0; char input [5]; while (1) {sum = 0; scanf ("% s ", input); for (I = 0; input [I]! = '\ 0'; I ++) sum = sum * 10 + input [I]-'0'; printf ("input = % d \ n", sum );} return 0 ;}
UseScanf
Functions are very dangerous. Even if you fix this bug, there are still many problems. What if the input string is too long? We know that array access is not checked out of bounds, soScanf
Write it out of bounds. The phenomenon is as follows:
$./Main123input = 12367 input = 6712345 input = 123407
Next we will use the debugger to see how this strange result came out [21].
$ GDB main... (GDB) startbreakpoint 1 at 0x80483b5: file main. c, line 5. starting program:/home/akaedu/main () at main. c: 55int sum = 0, I = 0; (GDB) n9sum = 0; (GDB) (Press ENTER) 10 scanf ("% s", input); (GDB) (Press enter directly) 12341_for (I = 0; input [I]! = '\ 0'; I ++) (GDB) P Input $1 = "12345"
Input
The array has only five elements.Scanf
Automatically added'\ 0'
, UseX
The command is clearer:
(GDB) x/7B input0xbfb8f0a7: 0x310x320x330x340x350x000x00
X
Command to print the content of the specified storage unit.7b
Is the print format,B
Indicates a group of each byte, and 7 indicates printing 7 groups [22], fromInput
The first byte of the array starts to print 7 bytes consecutively. The first five bytes areInput
The storage unit of the array prints the hexadecimal ASCII code.'1'
To'5'
, 6th bytes are written out of bounds'\ 0'
. According to the running result, the first four characters are correct to convert to numbers. The first 5th characters are incorrect, that isI
The cycle from 0 to 3 is correct. We set a condition breakpoint fromI
Equal to 4 to start single-step debugging:
(GDB) l6char input [5]; 78 while (1) {9sum = 0; 10 scanf ("% s", input); 11for (I = 0; input [I]! = '\ 0'; I ++) 12sum = sum * 10 + input [I]-'0'; 13 printf ("input = % d \ n", sum ); 14} 15 return 0; (GDB) B 12 if I = 4 breakpoint 2 at 0x80483e6: file main. c, line 12. (GDB) ccontinuing. breakpoint 2, main () at main. c: 1212sum = sum * 10 + input [I]-'0'; (GDB) P sum $2 = 1234
NowSum
Yes, it is 1234. According to the running result 123407, we know that the calculation in this step will definitely go wrong. The calculation should be 12340, that is to sayInput [4]
Certainly not'5'
It turns out that this reasoning is not rigorous:
(GDB) x/7B input0xbfb8f0a7: 0x310x320x330x340x350x040x00
Input [4]
It is indeed 0x35, and there is another possibility of generating 123407, that is, in the next cycle, 123450 is not added but subtracted from a number to get 123407. But is it not at the end of the string? How can there be a next loop? Note that the cyclic control condition isInput [I]! = '\ 0'
But it should have been 0x04 at the position of 0x00, so the loop will not end. Continue step:
(GDB) n11for (I = 0; input [I]! = '\ 0'; I ++) (GDB) P sum $3 = 12345 (GDB) n12sum = sum * 10 + input [I]-'0'; (GDB) x/7B input0xbfb8f0a7: 0x310x320x330x340x350x050x00
In the next cycle, the original 0x04 is inexplicably changed to 0x05. What is the problem? This cannot be explained for the time being, but the 123407 result can be explained. The result is 12345*10 + 0x05-0x30. Although the loop is repeated once, it will definitely exit the loop next time, because 0x05 is followed'\ 0'
.
input [4]
when is the next byte changed? You can use watchpoint for tracking. We know that the breakpoint is interrupted when the Program executes a Code line, the observation point is interrupted when the program accesses a storage unit. If we do not know where a storage unit is modified, the observation point is particularly useful. Next, we will delete the previously set breakpoint and execute the program from scratch. Repeat the previous input and use the watch
command to set the observation point, trace the byte following input [4]
(which can be expressed by input [5]
,
(GDB) delete breakpoints delete all breakpoints? (Y or N) y (GDB) startbreakpoint 1 at 0x80483b5: file main. c, line 5. starting program:/home/akaedu/main () at main. c: 55int sum = 0, I = 0; (GDB) n9sum = 0; (GDB) (Press ENTER) 10 scanf ("% s", input); (GDB) (Press enter directly) 12341_for (I = 0; input [I]! = '\ 0'; I ++) (GDB) Watch input [5] hardware watchpoint 2: input [5] (GDB) I watchpoints num type disp ENB address what2 HW watchpoint keep y input [5] (GDB) ccontinuing. hardware watchpoint 2: input [5] Old value = 0' \ 0' new value = 1' \ 001' 0x0804840c in main () at main. c: 1111for (I = 0; input [I]! = '\ 0'; I ++) (GDB) ccontinuing. hardware watchpoint 2: input [5] Old value = 1' \ 001' new value = 2' \ 002' 0x0804840c in main () at main. c: 1111for (I = 0; input [I]! = '\ 0'; I ++) (GDB) ccontinuing. hardware watchpoint 2: input [5] Old value = 2' \ 002 'New value = 3' \ 003' 0x0804840c in main () at main. c: 1111for (I = 0; input [I]! = '\ 0'; I ++)
ObviouslyFor
It changed at the beginning of the loop.Input [5]
The value of, and is to add 1 each time, while the Loop VariableI
Add 1 before each return to the beginning of the loop.Input [5]
Is variableI
In other words,I
Is followedInput
Array.
It is difficult for beginners to fix this bug. If you find this bug but do not expect array access to cross-border, you may first handle another bug that is easier to fix without looking at the cause: if the input is not a number but a letter or other symbol, the result can be calculated. This is obviously not correct. You can add a condition in the loop to check for invalid characters:
While (1) {sum = 0; scanf ("% s", input); for (I = 0; input [I]! = '\ 0'; I ++) {If (input [I] <'0' | input [I]> '9') {printf ("invalid input! \ N "); sum =-1; break;} sum = sum * 10 + input [I]-'0';} printf (" input = % d \ n ", sum );}
Then, you will be pleasantly surprised to find that not only will an error be reported when you enter a letter, but will also report an error if you enter too long:
$./Main123ainvalid input! Input =-1 deadinvalid input! Input =-11234578 invalid input! Input =-11234567890 abcdefinvalid input! Input =-123 input = 23
It seems that the two bugs have been solved together, but this is a solution to the symptoms. It seems that the input is too long, but it cannot be solved as long as the root cause is not found. When the condition changes, it may come up again, in the next section, you will see that it has emerged in a new form. Now, let's take a look at why an error is reported if the entered code is too long after the code is added to check for invalid characters. Finally, we will summarizeGDB
Command:
Table 10.3. GDB basic command 3
Command |
Description |
Watch |
Set observation points |
Info (or I) watchpoints |
View the observed points currently set |
X |
The content of the storage unit is printed from a certain position. It is regarded as byte, but it does not distinguish which byte belongs to which variable. |