这个功能有什么问题?

时间:2010-02-27 17:20:15

标签: c find

我今天遇到了问题。它有一个方法,我需要在该函数中找到问题。该函数的目标是将新行附加到传递的字符串。以下是代码

char* appendNewLine(char* str){
    int len = strlen(str);
    char buffer[1024];
    strcpy(buffer, str);
    buffer[len] = '\n';
    return buffer;
}

我已经确定了这种方法的问题。它那种直截了当。该方法可能使数组的索引超出范围。这不是我的疑问。在java中,我使用'\ n'作为换行符。 (我基本上是一名Java程序员,多年来我一直在C工作)。但我依稀记得'\ n'是表示C中字符串的终止。这也是这个程序的问题吗?

请告知。

13 个答案:

答案 0 :(得分:9)

此代码中有很多问题。

  1. strlen而不是strlent,除非你在那里有一个奇怪的库函数。
  2. 您正在堆栈上定义静态缓冲区。这是一个潜在的错误(也是一个安全错误),因为稍后您将字符串复制到它而不检查长度。 可能的解决方案可以是在堆上分配内存(使用strlen和malloc的组合),或者使用strncpy并接受字符串的截断。
  3. 附加'\ n'确实解决了添加新行的问题,但这会产生进一步的错误,因为该字符串当前不是空终止的。 解决方案:将'\ n'和'\ 0'追加为null以终止新字符串。
  4. 正如其他人所提到的,你正在返回一个指向局部变量的指针,这是一个严重的错误,并且会在短时间内使返回值损坏。
  5. 为了扩展您对这些问题的理解,请查看可能来自here的C样式字符串。另外,自学一下堆栈上分配的变量和堆上分配的变量之间的区别。

    编辑:AndreyT是正确的,长度的定义是有效的

答案 1 :(得分:7)

不,'\ n'是c中的换行符,就像在Java中一样(Java从C中获取)。您已经确定了一个问题:如果输入字符串比buffer长,则会写出buffer的结尾。更糟糕的是,您的return buffer;返回函数本地的内存地址,并在函数退出时停止存在。

答案 2 :(得分:5)

首先,这是一个功能,而不是一个程序。

此函数返回指向局部变量的指针。当函数退出时,通常在堆栈上创建的这些变量不再可用。

另一个问题是如果传递的长度超过1024个字符;在这种情况下,strcpy()将写入缓冲区。 一种解决方案是在动态内存中分配新缓冲区并返回指向该缓冲区的指针。缓冲区的大小应为len +2(所有字符+ newline + \0字符串终结符),但某人必须释放此缓冲区(可能还有初始缓冲区)以及)。

strlent()不存在,应该是strlen()但我认为这只是一个错字。

答案 3 :(得分:3)

此函数返回缓冲区,它是堆栈上的局部变量。一旦函数返回,缓冲区的内存就可以重新用于其他目的。

如果您打算从函数返回内存,则需要使用malloc或类似内容分配内存。

代码还有其他问题 - 您不能确保缓冲区足够大以包含您尝试复制到它的字符串,并且您不确保字符串以空终止符结束。

答案 4 :(得分:3)

C字符串以'\ 0'结尾。
而且你的目标是附加newLine,以下会很好(将节省你将整个字符串复制到缓冲区):

char* appendNewLine(char* str){
    while(*str != '\0') str++;  //assumming the string ended with '\0'
    *str++ = '\n';  //assign and increment the pointer
    *str = '\0';
    return str;  //optional, you could also send 0 or 1, whether 
                 //it was successful or not
}

编辑:
字符串应该有空间来容纳额外的'\ n',因为 OBJECTIVE 本身是追加的,这意味着添加到原始字符串,它可以安全地假设字符串有至少一个字符的空间!
但是,如果你不想做任何事情,

char* appendNewLine(char* str){
    int length = strlen(str);
    char *newStr = (char *)malloc(1 + length);
    *(newStr + length) = '\n';
    *(newStr + length + 1) = '\0';
    return newStr;
}

答案 5 :(得分:2)

在换行符后添加null:

buffer[len] = '\n';
buffer[len + 1] = 0;

答案 6 :(得分:2)

C中字符串的终止符是'\ 0'而不是'\ n'。它仅代表换行符。

答案 7 :(得分:2)

您的计划至少存在两个问题。

首先,您似乎想要构建一个字符串,但您永远不会将其终止。

其次,函数返回一个指向本地声明的缓冲区的指针。这样做是没有意义的。

答案 8 :(得分:1)

代码有几个问题:

  • 它可以缓冲溢出,因为buffer被硬编码为仅分配1024个字符。更糟糕的是,缓冲区甚至没有在堆中分配。
  • 换行符“字符”实际上取决于操作系统。严格来说,它只是Unix中的\n等等。在Windows和严格的互联网协议中,它是\r\n,例如。
  • 函数返回的字符串不以空值终止。这很可能不是你想要的。

另外,考虑到您在Java中的背景,以下是您应该考虑的一些事项:

  • 既然您正在使用C char*而不是(不可变的)Java字符串,那么您是否可以在原地添加换行符?
  • 在运行时不再检查数组访问权限,因此您必须非常小心超出范围。确保所有缓冲区都具有适当的大小。
  • 该语言没有标准的自动垃圾收集,因此如果您确实选择为字符串操作分配新的缓冲区,请确保正确管理内存并且不会在任何地方泄漏。

答案 9 :(得分:1)

char* appendNewLine(char* str){
    int len = strlen(str);
    char buffer[1024];
    strcpy(buffer, str);
    buffer[len] = '\n';
    return buffer;
}

另一个重要问题是缓冲变量;它应该是一个本地堆栈变量。一旦函数返回,它就会从堆栈中被销毁。并且返回指向缓冲区的指针可能意味着如果您尝试写入返回的指针(堆栈上地址的缓冲区地址),您将崩溃您的进程。

使用malloc代替

答案 10 :(得分:1)

我无视当地人的回归,正如其他人雄辩地解决了这一问题。

int len = strlen(str);
char buffer[1024];
...
buffer[len] = '\n';

如果strlen(str)> 1024,然后这个序列将超出声明的缓冲区的边界。同样如上所述,这可能(可能)不会被终止。

如果有可能,安全地追加新行

char buffer[1024];
strncpy(buffer, str, 1024); // truncate string if it is too long
int len = strlen(buffer);
if (len < 1022) {
   buffer[len] = '\n';
   buffer[len + 1] = '\0';
} 

注意:如果字符串太长,则会使截断的字符串不包含新行。

答案 11 :(得分:0)

C字符串必须以'\0'结尾。

buffer[len+1] = '\0';

您应该动态地将缓冲区分配为指向大小为len的char的指针:

char *buffer = malloc(len*sizeof(char));

答案 12 :(得分:-2)

也许\ n应该是\ r \ n。返回+换行。这就是我一直使用并为我工作的东西。