簡體   English   中英

即使獲得正確的輸出,仍然會出現“檢測到堆棧粉碎”錯誤

[英]Still getting “stack smashing detected” error even getting correct output

對於分配,我正在使用已經構建的3個函數( findStringremoveStringinsertString )來構建replaceString函數,該函數將s1字符串在source字符串中的第一次出現替換為s2字符串。 效果很好,除非s1是單個字符(例如"a" )或空字符串"" ,否則錯誤“堆棧已檢測到堆棧”將顯示在下面:

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  ----- */

當你做

char text[] = "a world";

您創建的數組只有8個字符(字符串和結尾的零)。 當用"hello"替換子字符串"a" ,您將寫出數組末尾,從而“破壞”堆棧。

而是設置數組的大小,使其足夠大以適合替換,例如

char text[16] = "a world";

超出數組末尾(或超出任何已分配內存的末尾)的寫操作會導致未定義的行為 未定義的行為可能很容易彎曲,很難追蹤,因為有時它似乎確實可以按預期工作。

char text[] = "a world"; 創建一個數組。 它的長度由其初始化程序決定,該初始化程序的長度為8個字符(不要忘記空終止符!)。 您要用五個字符替換一個字符,總共12個字符。對於數組而言,這太長了,所以溢出了。 那砸了堆棧。

您正在通過char text[] = "a world";在堆棧上分配固定寬度的字符串char text[] = "a world"; ,編譯器會在構建時自動確定為該r / w內存分配的空間量,該空間量是字符串的長度加上一個終止NULL字符的空間,在此特定示例中總計為8個字節。

您的代碼將嘗試在此內存區域的范圍之外進行寫入,並通過將其不應寫入的區域寫入堆棧而破壞堆棧,這也稱為堆棧粉碎。

您應該花一些時間來閱讀有關內存分段的信息,如下面的參考所述。 此外,如果堅持使用靜態分配緩沖區而不是通過malloc / calloc調用在堆上動態分配malloc ,那么一個好習慣就是通過宏使用公共常量,如果編譯器為C99,則使用const size_t兼容並支持可變長度數組(VLA)。

即:

#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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM