仍然得到“堆栈粉碎检测”错误甚至获得正确的输出

时间:2014-07-03 03:28:06

标签: c string replace

对于作业,我正在构建一个replaceString函数,使用我已构建的3个函数(findStringremoveStringinsertString)替换第一次出现的函数带有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  ----- */

3 个答案:

答案 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";

您将在内存中使用更多空间,但可以通过strlcatstrlcpy等编写更安全的代码,这样可以安全地保证写入的最大字节数,从而防止将来出现此类错误。 <强>参考


  1. 声明字符串与已分配字符串之间的区别,已访问2014-07-02,<https://stackoverflow.com/questions/16021454/difference-between-declared-string-and-allocated-string/16021546#16021546>