对于作业,我正在构建一个replaceString
函数,使用我已构建的3个函数(findString
,removeString
,insertString
)替换第一次出现的函数带有s1
字符串的source
字符串中的s2
字符串。它很好,除非s1
是单个字符(例如"a"
)或空字符串""
,否则会在其下方显示错误“stack smashing detected”:
hello, world
*** stack smashing detected ***: /home/noob/ex1008 terminated
======= Backtrace: =========
...
======= Memory map: ========
...
当我调用这样的函数时会发生这种情况:
char text[] = "a world";
replaceString ( text, "a", "hello," );
或
char text[] = " world";
replaceString ( text, "", "hello," );
但是,当我声明这样的数组长度时,可以消除此错误:
char text[10] = "a world";
replaceString ( text, "a", "hello," )
或者,如果s1的长度大于1:
char text[] = "the world";
replaceString ( text, "the", "hello," )
我不明白为什么它会像这样。当我输入单个字符串或空字符串时,有没有一种方法我不需要声明数组长度?请参阅下面的完整代码:
#include <stdlib.h>
#include <stdio.h>
int main ( int argc, char *argv[] )
{
char text[] = "a world";
void replaceString ( char source[], const char s1[], const char s2[] );
replaceString ( text, "a", "hello," );
printf ( "%s\n", text );
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */
/*
* === FUNCTION =========================================================
* Name: replaceString
* Description: Replaces first occurrence of s1 in source with s2.
* ========================================================================
*/
void replaceString ( char source[], const char s1[], const char s2[] )
{
int start, removeLength;
int findString ( const char source[], const char search[] );
void removeString ( char source[], const int start, const int remove );
void insertString ( char source[], const char insert[],
const int start );
start = findString ( source, s1 );
if ( start == -1 )
return;
for ( removeLength = 0; s1[removeLength]; removeLength++ );
removeString ( source, start, removeLength );
insertString ( source, s2, start );
} /* ----- end of function replaceString ----- */
/*
* === FUNCTION =========================================================
* Name: findString
* Description: Determines if one character string exists inside other
* string. If found, returns location in source string. If
* not, returns -1.
* ========================================================================
*/
int findString ( const char source[], const char search[] )
{
int i, j;
for ( i = 0; source[i]; i++ )
for ( j = 0; source[i + j] == search[j] || ! search [j]; j++ )
if ( ! search[j] )
return i;
return -1;
} /* ----- end of function findString ----- */
/*
* === FUNCTION =========================================================
* Name: removeString
* Description: Removes a specified number of characters from a character
* string.
* ========================================================================
*/
void removeString ( char source[], const int start,
const int remove )
{
char output[80];
int i, j = 0;
for ( i = 0; source[i]; i++ )
if ( i < start || i >= start + remove )
output[j++] = source[i];
output[j] = '\0';
for ( i = 0; output[i]; i++)
source[i] = output[i];
source[i] = '\0';
} /* ----- end of function removeString ----- */
/*
* === FUNCTION =========================================================
* Name: insertString
* Description: Inserts a string into another string.
* ========================================================================
*/
void insertString ( char source[], const char insert[],
const int start )
{
char output[80];
int i = 0, j = 0, k = 0;
while ( source[i] ) {
if ( i < start || ! insert[k] )
output[j++] = source[i++];
else
output[j++] = insert[k++];
}
output[j] = '\0';
for ( i = 0; output[i]; i++ )
source[i] = output[i];
source[i] = '\0';
} /* ----- end of function insertString ----- */
答案 0 :(得分:3)
当你这样做时
char text[] = "a world";
您创建一个只有8个字符的数组(字符串和终止零)。当您将子字符串"a"
替换为"hello"
时,您将在数组末尾之外写入,从而粉碎&#34;堆栈。
而是设置数组的大小,使其足够大以适应替换,例如
char text[16] = "a world";
超出数组末尾(或超出任何已分配内存的末尾)的写入会导致undefined behavior。未定义的行为可能是狡猾的,很难追踪,因为有时它可能似乎按预期工作。
答案 1 :(得分:1)
char text[] = "a world";
创建一个数组。它的长度由初始化器确定,初始化器长度为8个字符(不要忘记空终止符!)。您将一个字符替换为五个字符,总共为12个字符。对于数组来说,这太长了,所以您有一个超限。那打碎了堆栈。
答案 2 :(得分:1)
您正在通过char text[] = "a world";
在堆栈上分配一个固定宽度的字符串,其中编译器自动确定在构建时为此r / w内存分配的空间量,该长度是字符串加空间用于终止NULL字符,在此特定示例中为8个字节。
您的代码将尝试在此部分内存的范围之外编写,并通过写入不应该写入的区域来破坏您的堆栈,也称为堆栈粉碎。
您应该花一些时间阅读内存分段,请参阅下面的参考资料。另外,如果你坚持使用静态分配缓冲区而不是通过malloc
/ calloc
调用在堆上动态,那么进入的好习惯就是通过宏使用公共常量,或者如果您的编译器符合C99并且支持可变长度数组(VLA),则为const size_t
。
即:
#define MAX_BUF_LENGTH (1024)
char text[MAX_BUF_LENGTH] = "a world";
您将在内存中使用更多空间,但可以通过strlcat
,strlcpy
等编写更安全的代码,这样可以安全地保证写入的最大字节数,从而防止将来出现此类错误。
<强>参考强>
<https://stackoverflow.com/questions/16021454/difference-between-declared-string-and-allocated-string/16021546#16021546>