初步观察
鉴于此测试代码:
static void chkit(char *s, char *u)
{
printf("[%s] && [%s]", s, u);
UpdateString(s, u);
printf(" ==> [%s]\n", s);
}
int main(void)
{
char MainString[200] = "";
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "XYZ");
chkit(MainString, "XYZ");
chkit(MainString, "XYZ");
chkit(MainString, "DEF");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "XYZ");
chkit(MainString, "ABC");
chkit(MainString, "GHI");
return 0;
}
我得到的输出是:
[] && [ABC] ==> [ABC=1]
[ABC=1] && [ABC] ==> [ABC=2]
[ABC=2] && [ABC] ==> [ABC=3]
[ABC=3] && [XYZ] ==> [ABC=3:XYZ=1]
[ABC=3:XYZ=1] && [XYZ] ==> [ABC=3:XYZ=2]
[ABC=3:XYZ=2] && [XYZ] ==> [ABC=3:XYZ=3]
[ABC=3:XYZ=3] && [DEF] ==> [ABC=3:XYZ=3:DEF=1]
[ABC=3:XYZ=3:DEF=1] && [ABC] ==> [ABC=4:XYZ=3:DEF=1]
[ABC=4:XYZ=3:DEF=1] && [ABC] ==> [ABC=5:XYZ=3:DEF=1]
[ABC=5:XYZ=3:DEF=1] && [ABC] ==> [ABC=6:XYZ=3:DEF=1]
[ABC=6:XYZ=3:DEF=1] && [ABC] ==> [ABC=7:XYZ=3:DEF=1]
[ABC=7:XYZ=3:DEF=1] && [ABC] ==> [ABC=8:XYZ=3:DEF=1]
[ABC=8:XYZ=3:DEF=1] && [ABC] ==> [ABC=9:XYZ=3:DEF=1]
[ABC=9:XYZ=3:DEF=1] && [ABC] ==> [ABC=10:=3:DEF=1]
[ABC=10:=3:DEF=1] && [XYZ] ==> [ABC=10:=3:DEF=1:XYZ=1]
[ABC=10:=3:DEF=1:XYZ=1] && [ABC] ==> [ABC=11:3:DEF=1:XYZ=1]
[ABC=11:3:DEF=1:XYZ=1] && [GHI] ==> [ABC=11:3:DEF=1:XYZ=1:GHI=1]
当数字从 1 位增加到 2 位时,显然存在问题。
一个问题
在代码中:
if (nIsPresentFlag == 1)
for (j = 0; j < i; j++)
sprintf(workbuf, "%s%s=%s:", workbuf, pData[j][0], pData[j][1]);
您通过写入workbuf
并将其作为参数之一传递来调用未定义的行为。那简直是危险的。你有一定的几率侥幸逃脱,但“侥幸逃脱”是一个有效的术语——不能保证它会奏效。
当您将新号码格式化为空间不足时,会出现覆盖问题。
工作代码
下面的代码似乎工作:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static void UpdateString(char *MainString, char ToUpdate[20])
{
char *pData[50][2];
char *saveptr1 = NULL;
int i = 0;
int nIsPresentFlag = 0;
char workbuf1[200];
char workbuf[200];
char extra[16];
if (strlen(MainString) > 0)
strcat(MainString, ":");
strcpy(workbuf1, MainString);
pData[i][0] = strtok_r(workbuf1, "=", &saveptr1);
pData[i][1] = strtok_r(NULL, ":", &saveptr1);
if (pData[i][0])
i++;
while ((pData[i][0] = strtok_r(NULL, "=", &saveptr1)) != 0)
{
pData[i][1] = strtok_r(NULL, ":", &saveptr1);
i++;
}
for (int j = 0; j < i; j++)
{
if (strncmp(ToUpdate, pData[j][0], strlen(pData[j][0])) == 0)
{
unsigned int CdrCnt = atoi(pData[j][1]);
CdrCnt += 1;
pData[j][1] = extra;
sprintf(pData[j][1], "%u", CdrCnt);
nIsPresentFlag = 1;
break;
}
}
if (nIsPresentFlag == 1)
{
char *dst = workbuf;
for (int j = 0; j < i; j++)
{
int n = sprintf(dst, "%s=%s:", pData[j][0], pData[j][1]);
/* Broken if sprintf() returns -1 */
dst += n;
}
}
else
sprintf(workbuf, "%s%s=%d:", MainString, ToUpdate, 1);
workbuf[strlen(workbuf)-1] = '\0';
strcpy(MainString, workbuf);
}
static void chkit(char *s, char *u)
{
printf("[%s] && [%s]", s, u);
UpdateString(s, u);
printf(" ==> [%s]\n", s);
}
int main(void)
{
char MainString[200] = "";
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "XYZ");
chkit(MainString, "XYZ");
chkit(MainString, "XYZ");
chkit(MainString, "DEF");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "ABC");
chkit(MainString, "XYZ");
chkit(MainString, "ABC");
chkit(MainString, "GHI");
chkit(MainString, "PQRSTU");
chkit(MainString, "I");
chkit(MainString, "I");
chkit(MainString, "I");
chkit(MainString, "PQRSTU");
return 0;
}
它省略了memset()
操作;可以将空终止字符串复制到任意数据上,只要您不超出空终止符,就不会遇到任何问题。该变量extra
用于存储新的数字;它避免了数字从N变为N+1位时出现的问题。该函数sprintf()
返回它写入的字符数;用于将数据安全地添加到工作缓冲区。
示例输出
[] && [ABC] ==> [ABC=1]
[ABC=1] && [ABC] ==> [ABC=2]
[ABC=2] && [ABC] ==> [ABC=3]
[ABC=3] && [XYZ] ==> [ABC=3:XYZ=1]
[ABC=3:XYZ=1] && [XYZ] ==> [ABC=3:XYZ=2]
[ABC=3:XYZ=2] && [XYZ] ==> [ABC=3:XYZ=3]
[ABC=3:XYZ=3] && [DEF] ==> [ABC=3:XYZ=3:DEF=1]
[ABC=3:XYZ=3:DEF=1] && [ABC] ==> [ABC=4:XYZ=3:DEF=1]
[ABC=4:XYZ=3:DEF=1] && [ABC] ==> [ABC=5:XYZ=3:DEF=1]
[ABC=5:XYZ=3:DEF=1] && [ABC] ==> [ABC=6:XYZ=3:DEF=1]
[ABC=6:XYZ=3:DEF=1] && [ABC] ==> [ABC=7:XYZ=3:DEF=1]
[ABC=7:XYZ=3:DEF=1] && [ABC] ==> [ABC=8:XYZ=3:DEF=1]
[ABC=8:XYZ=3:DEF=1] && [ABC] ==> [ABC=9:XYZ=3:DEF=1]
[ABC=9:XYZ=3:DEF=1] && [ABC] ==> [ABC=10:XYZ=3:DEF=1]
[ABC=10:XYZ=3:DEF=1] && [XYZ] ==> [ABC=10:XYZ=4:DEF=1]
[ABC=10:XYZ=4:DEF=1] && [ABC] ==> [ABC=11:XYZ=4:DEF=1]
[ABC=11:XYZ=4:DEF=1] && [GHI] ==> [ABC=11:XYZ=4:DEF=1:GHI=1]
[ABC=11:XYZ=4:DEF=1:GHI=1] && [PQRSTU] ==> [ABC=11:XYZ=4:DEF=1:GHI=1:PQRSTU=1]
[ABC=11:XYZ=4:DEF=1:GHI=1:PQRSTU=1] && [I] ==> [ABC=11:XYZ=4:DEF=1:GHI=1:PQRSTU=1:I=1]
[ABC=11:XYZ=4:DEF=1:GHI=1:PQRSTU=1:I=1] && [I] ==> [ABC=11:XYZ=4:DEF=1:GHI=1:PQRSTU=1:I=2]
[ABC=11:XYZ=4:DEF=1:GHI=1:PQRSTU=1:I=2] && [I] ==> [ABC=11:XYZ=4:DEF=1:GHI=1:PQRSTU=1:I=3]
[ABC=11:XYZ=4:DEF=1:GHI=1:PQRSTU=1:I=3] && [PQRSTU] ==> [ABC=11:XYZ=4:DEF=1:GHI=1:PQRSTU=2:I=3]
我做了一些基本的检查valgrind
(并添加了一些动态内存分配),它提出了一个干净的健康状况。
注意诊断打印的样式。它显示了输入和输出,这很有帮助。并且它将字符串包含在一个独特的标记中(此处[]
),以便可以更容易地发现杂散空间等。