Issue
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;
}
Solution
Calls to strcpy
, memcpy
and 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
.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char buf[10] = "a678b";
int res = 0;
for (const char *s = buf; *s != '\0'; )
{
char* endptr;
int x = strtol(s, &endptr, 10);
if (s == endptr)
++endptr;
else
res += x;
s = endptr;
}
printf("%d", res);
}
This program produces the output:
678
Note also I changed the test for when strtol
doesn'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 if endptr
was advanced past the beginning of the string.
I also initialized res
to 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.
Answered By - paddy