我想修改一个这样的字符串: -
MainString="", ToUpdate="ABC" -> return# "ABC=1"
MainString="ABC=1", ToUpdate="ABC" -> return# "ABC=2"
MainString="ABC=2", ToUpdate="ABC" -> return# "ABC=3"
MainString="ABC=3", ToUpdate="XYZ" -> return# "ABC=3:XYZ=1"
MainString="ABC=3:XYZ=1", ToUpdate="XYZ" -> return# "ABC=3:XYZ=2"
MainString="ABC=3:XYZ=2", ToUpdate="XYZ" -> return# "ABC=3:XYZ=3"
我有以下功能:
void UpdateString(char *MainString, char ToUpdate[20])
{
char *pData[50][2];
char *saveptr1=NULL;
int i=0,j=0,nIsPresentFlag=0;
unsigned int CdrCnt=1;
char workbuf1[200];
char workbuf[200];
memset(workbuf,0,200);
memset(workbuf1,0,200);
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++;pData[i][0]=NULL; pData[i][1]=NULL;}
while((pData[i][0]=strtok_r(NULL,"=",&saveptr1)))
{
pData[i][1]=strtok_r(NULL,":",&saveptr1);
i++;
}
for(j=0;j<i;j++)
if(strncmp(ToUpdate,pData[j][0],strlen(pData[j][0]))==0)
{
CdrCnt=atoi(pData[j][1]);
CdrCnt+=1;
sprintf(pData[j][1],"%d",CdrCnt);
nIsPresentFlag=1;
break;
}
if(nIsPresentFlag==1)
for(j=0;j<i;j++)
sprintf(workbuf,"%s%s=%s:",workbuf,pData[j][0],pData[j][1]);
else
sprintf(workbuf,"%s%s=%d:",MainString,ToUpdate,1);
workbuf[strlen(workbuf)-1]='\0';
memset(MainString,0,200);
strcpy(MainString,workbuf);
}
奇怪的是,这个功能正在运行,但有时会导致带有segfault的核心转储。
这段代码有什么问题?我能管理上述任务的更好方法吗?
=============================================== ===============================
字符串声明:
char MainString[200];
电话就像:
UpdateString((char*)&MainString,"ABC");
答案 0 :(得分:5)
鉴于此测试代码:
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
并将其作为参数之一传递来调用未定义的行为。那简直太危险了。你有机会侥幸逃脱它,但是要离开&#39;是一个有效的术语 - 不保证它会起作用。
将新数字格式化为空间不足时会出现覆盖问题。
以下代码似乎有效:
#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
进行了一些基本检查(并添加了一些动态内存分配),它提出了一个干净的健康状况。
注意诊断打印的样式。它显示输入和输出,这是有帮助的。它用一个独特的标记(这里是[]
)包围字符串,这样就可以更容易地发现杂散空间等。