2011-04-19 34 views
2

我正在運行這個簡單的程序,我得到的輸出是一個「總線錯誤」。使用一些調試語句,我發現它發生的地方是在strcat()調用。運行一個簡單字符串C程序時總線錯誤

#include<stdio.h> 
#include<string.h> 
main() 
{ 
char *s = "this is "; 
char *s1 = "me"; 
strcat(s,s1); 
printf("%s",s); 
return 0; 
} 

我在MAC 64位操作系統上使用gcc編譯器來運行它。請讓我知道是否需要提供更多規格。

謝謝!

回答

7

一點背景:

表達"this is ""me"是字符串文字;它們分別是具有靜態範圍(意味着它們的存儲器在程序啓動時分配並保存直到程序退出)的9個和3個元素的char(C++中的const char)陣列。這個內存可能是也可能不是可寫的,這取決於平臺,所以試圖修改字符串文字會導致未定義的行爲(意味着編譯器可以從字面上做任何事情)。總之,你不能寫入字符串文字。

當您編寫strcat(s, s1);時,您遇到了兩個問題:首先,目標數組是字符串文字,正如我上面提到的那樣,它是不可寫的。其次,它不足以容納額外的字符;它的大小可以容納9個字符(包括0個終結符),但是你試圖存儲11個字符。這是一個緩衝區溢出,如果你破壞了一些重要的東西,這可能會導致壞事。

您必須分配一個可寫的目標緩衝區。您有幾種選擇:

  1. 你可以聲明數組這是大到足以容納結果字符串,雖然一般你不會知道有多大「足夠大」是在編譯時:

    
    char *s = "this is "; 
    char *s1 = "me"; 
    char target[11]; 
    strcpy(target, s); 
    strcat(target, s1); 
    // alternately, sprintf(target, "%s%s", s, s1); 
    

  2. 在C99中,可以聲明一個可變長度數組(VLA),其尺寸是不知道直到運行時:

    
    char *s = "this is "; 
    char *s1 = "me"; 
    char target[strlen(s) + strlen(s1) + 1]; 
    strcpy(target, s); 
    strcat(target, s1); 
    // alternately, sprintf(target, "%s%s", s, s1); 
    

  3. 可以使用動態分配一個目標緩衝器malloccalloc(硫5事實上是首選方法,因爲緩衝可以調整爲必要的,不像VLA):

    
    char *s = "this is "; 
    char *s1 = "me"; 
    char *target = malloc(strlen(s) + strlen(s1) + 1); 
    strcpy(target, s); 
    strcat(target, s1); 
    // or sprintf(target, "%s%s", s, s1); 
    ... 
    free(target); // when you're finished with the buffer 
    

+1

執行操作的各種可能性很好。謝謝! – Maverickgugu 2011-04-19 14:45:26

+0

「靜態範圍」? - 我認爲你要找的短語是「靜態存儲時間」。除此之外,一個很好的答案。 – paxdiablo 2011-04-20 03:06:23

8

"this is ""me"是字符串文字,它們可能位於地址空間的只讀部分。你不應該試圖修改這些。

char s[] = "this is "; 
char s1[] = "me"; 

這將確保文字被複制到堆棧 - 這是可寫的。然後你的後續strcat會溢出堆棧緩衝區,這同樣糟糕。

下面將工作 - 即使使用strcat而不是strncat是一般不好的做法。

#include <stdio.h> 
#include <string.h> 
int main() 
{ 
    char s[100] = "this is "; 
    char *s1 = "me"; 
    strcat(s,s1); 
    printf("%s",s); 
    return 0; 
} 
+3

'strcat'僅僅是不好的做法,那些不知道如何正確使用它。這些人應該堅持使用BASIC :-)但是你釘牢它+1。 – paxdiablo 2011-04-19 13:38:32

+1

@paxdiablo:是的,因此「一般」;) – Erik 2011-04-19 13:38:58

+0

哇,讓我記得很久以前發生在我身上的一個討厭的bug。我遇到了seg-faults,然後意識到這很難。 – BiGYaN 2011-04-19 13:41:50

2

您需要詳細瞭解字符串如何在C中工作以及字符數組和字符串文字之間的區別。

爲了使這項工作,把它改寫爲例說明如下:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(void) 
{ 
    char s[100] = "this is "; 
    char *s1 = "me"; 

    strcat(s, s1); 

    printf("%s", s); 

    return EXIT_SUCCESS; 
} 

數點:

  1. main()回報int
  2. 符號EXIT_SUCCESS(來自<stdlib.h>比0更清楚)。
  3. 一個不帶參數的函數應在C中聲明爲void。對於main(),空括號無效。
+4

我沒有發現'EXIT_SUCCESS'比零更清晰;它只是混亂。像「FALSE」這樣的宏也一樣。 – 2011-04-19 13:42:10

+0

感謝您的詳細描述。我想我應該開始採用更正式的編程風格。但是我無法理解EXIT_SUCCESS如何在更好的調試過程中提供幫助? – Maverickgugu 2011-04-19 13:47:19