2010-11-30 105 views
1

第二次調用strcat這裏是產生分段錯誤,爲什麼?strcat分段錯誤

#include <unistd.h> 
#include<stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdlib.h> 
#include <string.h> 
#include <pthread.h> 

int main (int argc, char * argv[]) 
{ 
     char command[250]; 

     //if(scanf("%199s", command) == 1) 

      gets(command); 
      puts(command); 

     int pipeIntId; 

     char whitespaceseparator[2]=" "; 

     char pidstring [30]; 

     int pid= getpid(); 

     sprintf(pidstring,"%d", pid); 

     char * whitespace_and_pid; 

     whitespace_and_pid = strcat(whitespaceseparator,pidstring); 


     char * command_and_pid; 

     command_and_pid=strcat(command,whitespace_and_pid); // here's the problem, I guess 


      if((mkfifo("pipe"/*pipeName*/,0666))==-1) 
      { 
       perror("error creating pipe 1"); 
      exit(1); 
      } 

     if((pipeIntId=open("pipe",/*pipeName*/O_WRONLY))==-1) 
     { 
      perror("error creating pipe 2"); 
      exit(1); 
     } 


     int written; 

     written=write(pipeIntId,command_and_pid,250); // send the command + the pid 


     close(pipeIntId); 

    return 0; 
} 
+0

我解決了這個問題,使用第一個答案在這裏http://stackoverflow.com/questions/308695/c-string-concatenation – andandandand 2010-11-30 01:20:07

回答

4

我試過了你的代碼,並且在第二個strcat()上看到了段錯誤。我發現command[250]whitespaceseparator[2]之後分配在棧上我的系統上:

(gdb) p &whitespaceseparator 
$1 = (char (*)[2]) 0xbf90acd4 
(gdb) p &command 
$2 = (char (*)[250]) 0xbf90acd6 

例如(這裏command開始"foo..."),東西都奠定了這樣的:

whitespaceseparator 
    | 
    |  command 
    |  | 
    v  v 
+---+---+---+---+---+---+---+---+ 
|' '| 0 |'f'|'o'|'o'|'.'|'.'|'.'| ... 
+---+---+---+---+---+---+---+---+ 

我不能保證你的系統上同樣的情況在堆棧上當地人(佈局甚至不同的版本相同的編譯器之間變化),但似乎很可能。在我的,這裏正是發生了什麼:

正如其他人所說,strcat()追加第二個字符串到第一個(和結果將等於第一個參數)。所以,第一個strcat()溢出whitespaceseparator[](並返回whitespaceseparator作爲whitespace_and_pid):

+---+---+---+---+---+---+---+---+ 
|' '|'1'|'2'|'3'|'4'| 0 |'.'|'.'| ... 
+---+---+---+---+---+---+---+---+ 

第二strcat()嘗試在command追加whitespace_and_pid(== whitespaceseparator)到該字符串。副本的第一個字符將在command覆蓋串的終止0:

| ===copy===> | 
    v     v 
+---+---+---+---+---+---+---+---+ 
|' '|'1'|'2'|'3'|'4'|' '|'.'|'.'| ... 
+---+---+---+---+---+---+---+---+ 

副本繼續...

 | ===copy===> | 
     v     v 
+---+---+---+---+---+---+---+---+ 
|' '|'1'|'2'|'3'|'4'|' '|'1'|'.'| ... 
+---+---+---+---+---+---+---+---+ 

      | ===copy===> | 
      v     v 
+---+---+---+---+---+---+---+---+ 
|' '|'1'|'2'|'3'|'4'|' '|'1'|'2'| ... 
+---+---+---+---+---+---+---+---+ 

,並進行復制" 1234 1234 1234" ......直到它脫落進程地址空間的結尾,此時您將收到段錯誤。

1

您的獲取調用可能已添加足夠多的字符,在任何時候都會導致未定義的行爲。

3

strcat不符合您的想法。它修改第一個參數指向的字符串。在這種情況下,該字符串包含在一個2字節的數組中,因此該字符串溢出。

+0

哦,我從這裏http://www.thinkage.ca/english/gcos /expl/c/lib/strcat.html。我很好奇它爲什麼它第一次運行。 – andandandand 2010-11-30 01:19:22

+0

我不認爲它在第一次運行時「工作」:將`pidstring`複製到`whitespaceseparator`的末尾是未定義的行爲,這並不意味着它必然會立即崩潰。馬修的回答有一個非常合理的解釋,爲什麼你會看到你所表示的一個崩潰,假設你的實現和他的一樣。 – 2010-11-30 02:26:04

+0

不,我不是說它使用這種帶有空白分隔符的pidstring的情況。它在第一次使用足夠大小的緩衝區時運行,在這種情況下將whitespaceseparator的大小更改爲較大的值也不會使其工作。 – andandandand 2010-11-30 03:29:50

1

whitespaceseparator不足以包含連接的字符串,所以導致未定義的行爲。

使用gets通常也被忽視。

1

strcat通常是不安全的,因爲它可以愉快地溢出緩衝區,就像它在你的情況一樣。

首先,whitespaceseparator只有兩個字節大?你確定這就是你想要的嗎?你連接pidstring它?我認爲你的觀點混淆了。

一般來說,如果你對緩衝區大小不是很小心的話,strcat會導致難以調試的崩潰。有更安全的選擇。

2

爲避免緩衝區溢出錯誤,但使用strcat您應該使用strncat函數。

1

「String concatenation」是學習C時應該放棄的習慣用法。不僅會導致大量帶有溢出緩衝區的錯誤;它也是超效率的。在你的代碼中,你可以只包含snprintf格式字符串中的空格(你應該用它來代替sprintf)。

只要有可能,嘗試使用snprintf在一個步驟中完全組裝字符串。這將所有的緩衝區長度檢查合併到一個地方,並且很難弄錯。您也可以調用snprintf,使用0大小的參數來獲取組合字符串的長度,以便找出要分配的大小,如果輸出的大小未預先知道(您應該再分配一個字節這個長度使空終止符不會截斷你的輸出)。