2008-11-21 55 views
240

我在C工作,我必須連接幾件事情。如何在C中連接const/literal字符串?

現在我有這樣的:

message = strcat("TEXT ", var); 

message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar)); 

現在,如果你在C我敢肯定你意識到這給你一個分割錯誤當您嘗試運行的經驗。那麼我該如何解決這個問題?

+6

我想建議你使用的strlcat提供,而不是strcat的! http://www.gratisoft.us/todd/papers/strlcpy.html – 2008-11-21 13:37:49

回答

271

在C中,「strings」只是數組。因此,您不能將它們與其他「字符串」直接連接起來。

可以使用strcat功能,附加字符串指向src到字符串的結尾由dest指出:

char *strcat(char *dest, const char *src); 

這裏是一個example from cplusplus.com

char str[80]; 
strcpy(str, "these "); 
strcat(str, "strings "); 
strcat(str, "are "); 
strcat(str, "concatenated."); 

對於第一個參數,您需要提供目標緩衝區本身。目標緩衝區必須是char數組緩衝區。例如:char buffer[1024];

確保第一個參數有足夠的空間來存儲您要拷貝的內容。如果對您有用,使用以下功能會更安全:strcpy_sstrcat_s,您明確必須指定目標緩衝區的大小。

注意:字符串文字不能用作緩衝區,因爲它是一個常量。因此,你總是必須爲緩衝區分配一個char數組。

strcat的返回值可以簡單地忽略,它只返回與第一個參數傳入的指針相同的指針。這是那裏的便利,並允許您鏈調用成一行代碼:

strcat(strcat(str, foo), bar); 

那麼如下的問題可以解決:

char *foo = "foo"; 
char *bar = "bar"; 
char str[80]; 
strcpy(str, "TEXT "); 
strcat(str, foo); 
strcat(str, bar); 
+45

您能否以粗體字「請非常小心......」?這不能夠強調。濫用strcat,strcpy和sprintf是不穩定/不安全軟件的核心。 – plinth 2008-11-21 13:33:10

3

這是不確定的行爲,以嘗試修改字符串文字,這是什麼樣的:

strcat ("Hello, ", name); 

會試圖做。它會嘗試將name字符串添加到字符串文字"Hello, "的末尾,該字符串的定義不明確。

試試這個。它實現了你看起來是試圖做:

char message[1000]; 
strcpy (message, "TEXT "); 
strcat (message, var); 

這將創建一個緩衝區面積允許修改,然後拷貝這兩個字符串文字等文本。請注意緩衝區溢出。如果你控制輸入數據(或者事先檢查它),那麼使用像我這樣的固定長度的緩衝區是很好的。否則,您應該使用緩解策略,例如從堆中分配足夠的內存以確保您可以處理它。換句話說,類似於:

const static char TEXT[] = "TEXT "; 

// Make *sure* you have enough space. 

char *message = malloc (sizeof(TEXT) + strlen(var) + 1); 
if (message == NULL) 
    handleOutOfMemoryIntelligently(); 
strcpy (message, TEXT); 
strcat (message, var); 

// Need to free message at some point after you're done with it. 
4

strcat()的第一個參數需要能夠爲連接字符串保留足夠的空間。因此,分配一個足夠空間的緩衝區來接收結果。

char bigEnough[64] = ""; 

strcat(bigEnough, "TEXT"); 
strcat(bigEnough, foo); 

/* and so on */ 

的strcat()將串聯的第一個參數的第二個參數,並將結果存儲在第一個參數,返回的char *僅僅是這第一個參數,只爲了您的方便。

你沒有得到一個新分配的字符串,第一個和第二個參數連接起來,我猜你會根據你的代碼預期的。

1

您試圖將一個字符串複製到靜態分配的地址中。你需要進入緩衝區。

具體做法是:

...略...

目的地

Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string. 

...略...

http://www.cplusplus.com/reference/clibrary/cstring/strcat.html

這裏有一個例子如好。

194

避免在C代碼中使用strcat。最乾淨,最重要的,最安全的方法是使用snprintf

char buf[256]; 
snprintf(buf, sizeof buf, "%s%s%s%s", str1, str2, str3, str4); 

一些評論提出了一個問題,參數的數目可能不符合格式字符串和代碼仍然編譯,但大多數編譯器已經問題如果是這樣的話,會發出警告。

+0

...但沒有對sizeof運算符的不必要的和易混淆的括號。只有當你想要一個實際類型的大小,而不是一個對象時才需要這些。寵物提示,抱歉。 – unwind 2008-11-21 13:23:38

+0

這可以說是找出緩衝區大小的最佳方法,除非給出指針。如果你有一個指針,你會傳遞它指向的緩衝區的長度。 – 2008-11-21 13:26:57

+3

跳棋,他在談論圍繞「buf」大小的論點的括號。如果參數是表達式,則不需要它們。但我不明白你爲什麼低調。我認爲你的答案是最好的,即使它是c99。 (也許是因爲他們不同意!lamers!)+1 – 2008-11-21 13:27:27

1

如果你有C的經驗,你會注意到字符串只是最後一個字符爲空字符的char數組。

現在這很不方便,因爲您必須找到最後一個字符才能追加內容。 strcat會爲你做到這一點。

因此,strcat通過第一個參數搜索空字符。然後它將用第二個參數的內容替換它(直到它以null結尾)。

現在,讓我們通過您的代碼:

message = strcat("TEXT " + var); 

在這裏,您要添加的東西的指針爲「TEXT」(的「TEXT」類型是爲const char *指針。)。

這通常不起作用。另外修改「TEXT」數組將不起作用,因爲它通常放置在一個常量段中。

message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar)); 

這可能會更好,除非您再次嘗試修改靜態文本。 strcat不會爲結果分配新的內存。

我提議做這樣的事情,而不是:

sprintf(message2, "TEXT %s TEXT %s", foo, bar); 

閱讀的sprintf的文檔,以檢查它的選項。

現在一個重要的觀點:

確保緩衝區有足夠的空間來保存文本和空字符。有幾個函數可以幫助你,例如,爲你分配緩衝區的strncat和特殊版本的printf。 不確保緩衝區大小將導致內存損壞和可遠程利用的錯誤。

18

民間,使用STR Ñ CPY(),STR Ñ貓(),或S ñ printf()的。
超出您的緩衝區空間將會破壞內存中的任何其他內容!
(並且記住允許空格用於結尾零'\ 0'字符!)

+2

不僅要記住爲NULL字符留出空間,還需要記住*添加* NULL字符。 strncpy和strncat不會爲你做。 – 2008-11-21 13:36:36

+0

呃? strncpy()和strncat()確定添加終止字符。事實上,他們添加了太多。至少只要緩衝區中留有空間,這對這些調用來說是一個巨大的陷阱。不建議。 – unwind 2008-11-21 13:42:56

5

不要忘記初始化輸出緩衝區。第一個參數的strcat必須是一個空值終止字符串分配得到的字符串足夠的額外空間:

char out[1024] = ""; // must be initialized 
strcat(out, null_terminated_string); 
// null_terminated_string has less than 1023 chars 
17

另外的malloc和realloc是有用的,如果你不知道的時間提前許多字符串是如何被連接在一起。

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

void example(const char *header, const char **words, size_t num_words) 
{ 
    size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */ 
    char *message = (char*) malloc(message_len); 
    strncat(message, header, message_len); 

    for(int i = 0; i < num_words; ++i) 
    { 
     message_len += 1 + strlen(words[i]); /* 1 + for separator ';' */ 
     message = (char*) realloc(message, message_len); 
     strncat(strncat(message, ";", message_len), words[i], message_len); 
    } 

    puts(message); 

    free(message); 
} 
4

正如人們指出的那樣,字符串處理有了很大的改進。所以你可能想學習如何使用C++字符串庫而不是C風格的字符串。不過這裏是純C的解決方案

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

void appendToHello(const char *s) { 
    const char *const hello = "hello "; 

    const size_t sLength  = strlen(s); 
    const size_t helloLength = strlen(hello); 
    const size_t totalLength = sLength + helloLength; 

    char *const strBuf = malloc(totalLength + 1); 
    if (strBuf == NULL) { 
     fprintf(stderr, "malloc failed\n"); 
     exit(EXIT_FAILURE); 
    } 

    strcpy(strBuf, hello); 
    strcpy(strBuf + helloLength, s); 

    puts(strBuf); 

    free(strBuf); 

} 

int main (void) { 
    appendToHello("blah blah"); 
    return 0; 
} 

我不知道它是否是正確的/安全的,但現在我找不到更好的辦法來做到這一點的ANSI C.做

3

最好的方法它不具有有限緩衝器大小是通過使用asprintf()

char* concat(const char* str1, const char* str2) 
{ 
    char* result; 
    asprintf(&result, "%s%s", str1, str2); 
    return result; 
} 
0

嘗試類似於這樣:

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

int main(int argc, const char * argv[]) 
{ 
    // Insert code here... 
    char firstname[100], secondname[100]; 
    printf("Enter First Name: "); 
    fgets(firstname, 100, stdin); 
    printf("Enter Second Name: "); 
    fgets(secondname,100,stdin); 
    firstname[strlen(firstname)-1]= '\0'; 
    printf("fullname is %s %s", firstname, secondname); 

    return 0; 
} 
1

甲假設你有一個char [fixed_size]而不是char *,你可以使用一個單一的創造性的宏來以一個<<cout<<like的順序一次完成所有的操作(「寧可%s不相交%s \ n」,「than」,「 printf樣式格式「)。如果您正在使用的嵌入式系統的工作,這種方法也可以讓你離開了malloc和大*printf家庭像snprintf()功能

#include <unistd.h> //for the write example 
//note: you should check if offset==sizeof(buf) after use 
#define strcpyALL(buf, offset, ...) do{ \ 
    char *bp=(char*)(buf+offset); /*so we can add to the end of a string*/ \ 
    const char *s, \ 
    *a[] = { __VA_ARGS__,NULL}, \ 
    **ss=a; \ 
    while((s=*ss++)) \ 
     while((*s)&&(++offset<(int)sizeof(buf))) \ 
      *bp++=*s++; \ 
    if (offset!=sizeof(buf))*bp=0; \ 
}while(0) 

char buf[256]; 
int len=0; 

strcpyALL(buf,len, 
    "The config file is in:\n\t",getenv("HOME"),"/.config/",argv[0],"/config.rc\n" 
); 
if (len<sizeof(buf)) 
    write(1,buf,len); //outputs our message to stdout 
else 
    write(2,"error\n",6); 

//but we can keep adding on because we kept track of the length 
//this allows printf-like buffering to minimize number of syscalls to write 
//set len back to 0 if you don't want this behavior 
strcpyALL(buf,len,"Thanks for using ",argv[0],"!\n"); 
if (len<sizeof(buf)) 
    write(1,buf,len); //outputs both messages 
else 
    write(2,"error\n",6); 
  • 注1(這從抱怨* printf的太保持dietlibc)你通常不會像這樣使用argv [0] - 只是一個例子
  • 注意2,你可以使用任何輸出char *的函數,包括像itoa()這樣的非標準函數來將整數轉換爲字符串類型。
  • 注3,如果你已經使用printf的程序中的任何地方,沒有理由不使用的snprintf(),因爲編譯後的代碼將更大(但內聯和顯著更快)
9

字符串也可以在編譯時連接。

#define SCHEMA "test" 
#define TABLE "data" 

const char *table = SCHEMA "." TABLE ; // note no + or . or anything 
const char *qry =    // include comments in a string 
    " SELECT * "    // get all fields 
    " FROM " SCHEMA "." TABLE /* the table */ 
    " WHERE x = 1 "    /* the filter */ 
       ; 
2

您可以編寫自己的功能,做同樣的事情strcat()但是這不會改變任何東西:

#define MAX_STRING_LENGTH 1000 
char *strcat_const(const char *str1,const char *str2){ 
    static char buffer[MAX_STRING_LENGTH]; 
    strncpy(buffer,str1,MAX_STRING_LENGTH); 
    if(strlen(str1) < MAX_STRING_LENGTH){ 
     strncat(buffer,str2,MAX_STRING_LENGTH - strlen(buffer)); 
    } 
    buffer[MAX_STRING_LENGTH - 1] = '\0'; 
    return buffer; 
} 

int main(int argc,char *argv[]){ 
    printf("%s",strcat_const("Hello ","world")); //Prints "Hello world" 
    return 0; 
} 

如果兩個串在一起的超過1000個字符長,將下調1000個字符的字符串。您可以更改MAX_STRING_LENGTH的值以滿足您的需求。

1
int main() 
{ 
    char input[100]; 
    gets(input); 

    char str[101]; 
    strcpy(str, " "); 
    strcat(str, input); 

    char *p = str; 

    while(*p) { 
     if(*p == ' ' && isalpha(*(p+1)) != 0) 
      printf("%c",*(p+1)); 
     p++; 
    } 

    return 0; 
} 
0

這是我的解決方案

#include <stdlib.h> 
#include <stdarg.h> 

char *strconcat(int num_args, ...) { 
    int strsize = 0; 
    va_list ap; 
    va_start(ap, num_args); 
    for (int i = 0; i < num_args; i++) 
     strsize += strlen(va_arg(ap, char*)); 

    char *res = malloc(strsize+1); 
    strsize = 0; 
    va_start(ap, num_args); 
    for (int i = 0; i < num_args; i++) { 
     char *s = va_arg(ap, char*); 
     strcpy(res+strsize, s); 
     strsize += strlen(s); 
    } 
    va_end(ap); 
    res[strsize] = '\0'; 

    return res; 
} 

,但你需要指定你要多少字符串來連接

char *str = strconcat(3, "testing ", "this ", "thing");