如果传递了长字符串,则获得以下代码的双倍空闲。 我尝试过各种各样的事情。如果我删除了自由线,它会消失。 不知道为什么会这样。
void format_str(char *str1,int l,int o) {
char *s = malloc(strlen(str1)+1);
char *s1=s, *b = str1;
int i=0;
while(*str1!='\0') {
i++;
*s1++=*str1++;
if(i>=l) {
if(*str1!=',') {
continue;
}
*s1++=*str1++;
*s1++='\n';
for(i=0;i<o;i++) {
*s1++=' ';
}
i = 0;
}
}
*s1 = '\0';
strcpy(b,s);
free(s);
}
答案 0 :(得分:5)
您可能没有在s
中为您要复制的数据量分配足够的空间。我不知道你的逻辑在做什么,但我看到像
*s1++=*str1++;
*s1++='\n';
您要为s
中的单个字符复制多个字符s1
(通过str1
)。
对于所有可计算的爱,使用更好的变量名称!
答案 1 :(得分:0)
你几乎肯定会破坏堆。例如:
int main()
{
char original[1000] = "some,,,string,,, to,,,,format,,,,,";
printf( "original starts out %u characters long\n", strlen(original));
format_str( original, 6, 6);
printf( "original is now %u characters long\n", strlen(original));
return 0;
}
要求malloc()
分配的缓冲区大小远大于strlen(str1)+1
。具体来说,它必须至少63字节长(因为函数在问题中编码,分配的大小为35字节)。
如果您需要更具体的帮助,则应描述您要执行的操作(例如l
和o
的参数是什么?)。
答案 2 :(得分:0)
为了心理健康,我会尝试重新格式化您的代码并猜测重命名变量。
void format_str(char *str, int minlen, int indent)
{
char *tmpstr = malloc( strlen(str) + 1 ); // here is the problem
char *wrkstr = tmpstr, *savestr = str;
int count = 0;
while ( *str != '\0' ) {
count++;
*wrkstr++ = *str++;
if ( count >= minlen ) {
if ( *str != ',' ) {
continue;
}
*wrkstr++ = *str++;
*wrkstr++ = '\n';
for ( count = 0; count < indent; count++ ) {
*wrkstr ++= ' ';
}
count = 0;
}
}
*wrkstr = '\0';
strcpy(savestr,tmpstr);
free(tmpstr);
}
正如其他人指出的那样,你没有为临时字符串分配足够的空间。
您的代码中还有另外两个问题(其中一个是主要问题)。
您可能应该通过检查str
不是NULL
来验证您的参数,也可能minlen
和indent
不是否定的。然而,这并不重要,因为NULL
str只是段错(标准库字符串函数的相同行为),minlen
和/或indent
的值低于1只是表现为0
主要问题是str
中你有多少空间。您在格式化过程中盲目地增长字符串,然后将其复制回相同的内存。这是一个等待发生的缓冲区溢出(具有潜在的严重安全隐患,特别是如果str
恰好指向堆栈)。
修复它:
您应该分配足够的空间。
您应该返回已分配的字符串并规定调用者负责释放它(如strdup
那样)或添加一个参数来指定str
中可用的空间然后避免任何工作,如果不存储格式化的字符串。
答案 3 :(得分:0)
用例是需要有可能进行干运行的一个很好的例子。
我建议您修改代码:
ssize_t format_str(const char * input, int p1, int p2, char * output);
1目标缓冲区应由函数调用者通过传递给函数的参数òutput
提供
2函数应返回写入目标缓冲区的字符数(负值可能表示任何类型的错误)
3如果作为output
传递的值为NULL,则函数不复制任何内容,只是解析input
引用的数据并确定将写入的字符数目标缓冲区并返回此值。
然后使用转换函数,应该调用它两次,如下所示:
char * input = "some,,test , data,,, ...";
int p1 = <some value>, p2 = <some other value>;
ssize_t ssizeOutput = format_str(input, p1, p2, NULL)
if (0 > ssizeOutput)
{
exit(EXIT_FAILURE);
}
else if (0 < ssizeOutput)
{
char * output = calloc(ssizeOutput, sizeof(*output));
if (!output)
{
exit(EXIT_FAILURE);
}
ssizeOutput = format_str(input, p1, p2, output);
if (0 > ssizeOutput)
{
exit(EXIT_FAILURE);
}
}
答案 4 :(得分:0)
正如其他人所指出的那样,堆内存最有可能被破坏,因为代码写入超出分配内存的末尾。
验证内存是否损坏很简单。在函数开始时保存str1的长度,我们将其命名为'len_before'。在调用free()之前,再次获取字符串长度,并将其命名为“len_after”。
如果(len_after&gt; len_before)那么我们就会发生致命错误。
一个相对简单的修复方法是传递str1可以长到的最大长度, malloc那么大的内存并在超过最大长度之前停止,即用空值截断它但保持在限制范围内。
int len_before, len_after;
len_before = strlen(str1) + 1;
.
. /* Rest of the code. */
.
len_after = strlen(str1) + 1;
if (len_after > len_before) {
printf("fatal error: buffer overflow by %d bytes.\n", len_after - len_before);
exit(1);
}
free(s);