I meet one strange problem while using gcc for c lib in strcpy and strtol function. Test on two situation and get the very different results.
//#The bad code is "res=68"
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int main() {
char buf[10];
char* endptr;
int x;
int res;
memset(buf, 0, sizeof(buf));
res=0;
strcpy(buf, "a678b");
while (*(buf) != '\0') {
x = strtol(buf, &endptr, 10);
if (x == 0) {
strcpy(buf, (endptr + 1));
}
else {
strcpy(buf, endptr);
}
res+= x;
}
printf("%d", res);
return 0;
}
After change to the following area, it can get the right value: 678. But, why?
while (*(buf) != '\0') {
x = strtol(buf, &endptr, 10);
if (x == 0) {
memset(kk, 0, sizeof(kk)); // add this
strcpy(kk, (endptr + 1));// add this
strcpy(buf, kk);
}
else {
strcpy(buf, endptr);
}
res+= x;
}
Calls to
strcpy,memcpyand friends are not allowed to use memory that overlaps. If the memory overlaps, the behavior is undefined. For short copies like you're doing, this will very likely produce strange results due to optimizations that copy multiple bytes at a time.There is a function that is designed for overlapping memory, called
memmove.However, you shouldn't need to use these functions at all. I have updated your program below to achieve this by simply walking a pointer through your string. There seems to be no need to keep copying it back to the beginning of
buf.This program produces the output:
Note also I changed the test for when
strtoldoesn't read a number. The return value 0 can be perfectly valid. The proper way to test if it actually parsed a number is to check ifendptrwas advanced past the beginning of the string.I also initialized
resto 0, because in your program you did not initialize it before adding values to it. That is also undefined behavior.So to summarize, you had a few cases of undefined behavior in your program due to misuse of standard library functions and not initializing memory.