2

如果通过了长字符串,则可以免费获得以下代码。我尝试了各种各样的事情。如果我删除 free(s) 行,它就会消失。不知道为什么会这样。

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);
}
4

5 回答 5

5

您可能没有s为要复制的数据量分配足够的空间。我不知道你的逻辑到底在做什么,但我看到了类似的东西

        *s1++=*str1++;
        *s1++='\n';

您将多个字符复制到s(via s1) 中的单个字符str1

为了热爱所有可计算的事物,请使用更好的变量名!

于 2012-09-20T00:38:30.477 回答
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 个字节)。

如果您需要更具体的帮助,您应该描述您正在尝试做什么(例如参数lo用途是什么?)。

于 2012-09-20T01:23:48.493 回答
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不是否定来验证您的论点。然而这并不重要,因为NULLstr 只会出现段错误(标准库字符串函数的相同行为)和低于 1 的值minlen和/或indent只是表现得好像它们是 0。

主要问题是你有多少空间str。您在格式化期间盲目地增长字符串,然后将其复制回同一内存。这是等待发生的缓冲区溢出(具有潜在的严重安全隐患,特别是如果str碰巧指向堆栈)。

要解决这个问题:

  • 您应该分配足够的空间。

  • 您应该返回分配的字符串并规定调用者负责释放它(就像这样strdup做),或者添加一个指定可用空间的参数,str然后如果不足以存储格式化的字符串,则避免任何工作。

于 2012-09-20T02:23:38.480 回答
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);
  }
}
于 2012-09-20T08:09:23.947 回答
0

正如其他人指出的那样,堆内存很可能会损坏,因为代码写入超出了分配内存的末尾。

验证内存是否损坏很简单。在函数开始时保存 str1 的长度,我们将其命名为“len_before”。在调用 free() 之前,再次获取字符串长度并将其命名为“len_after”。

如果 (len_after > len_before) 那么我们有一个致命错误。

一个相对简单的解决方法是传入 str1 可以增长到的最大长度,分配那么多内存并在超过最大长度之前停止,即用 null 截断它但保持在限制范围内。

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);
于 2012-09-30T05:40:10.733 回答