我在 C 中工作,我必须连接一些东西。
现在我有这个:
message = strcat("TEXT ", var);
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
现在,如果您有 C 方面的经验,我相信您会意识到,当您尝试运行它时,这会给您带来分段错误。那么我该如何解决呢?
我在 C 中工作,我必须连接一些东西。
现在我有这个:
message = strcat("TEXT ", var);
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
现在,如果您有 C 方面的经验,我相信您会意识到,当您尝试运行它时,这会给您带来分段错误。那么我该如何解决呢?
在 C 中,“字符串”只是普通char
数组。因此,您不能直接将它们与其他“字符串”连接起来。
您可以使用该strcat
函数,它将指向的字符串附加到指向的字符串src
的末尾dest
:
char *strcat(char *dest, const char *src);
char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");
对于第一个参数,您需要提供目标缓冲区本身。目标缓冲区必须是 char 数组缓冲区。例如:char buffer[1024];
确保第一个参数有足够的空间来存储您要复制的内容。如果您可以使用,使用以下函数会更安全:strcpy_s
并且strcat_s
您必须明确指定目标缓冲区的大小。
注意:字符串文字不能用作缓冲区,因为它是一个常量。因此,您总是必须为缓冲区分配一个字符数组。
的返回值strcat
可以简单地忽略,它只返回与作为第一个参数传入的指针相同的指针。它是为了方便起见,并允许您将调用链接到一行代码中:
strcat(strcat(str, foo), bar);
所以你的问题可以解决如下:
char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);
字符串也可以在编译时连接。
#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 */
;
伙计们,使用 str n cpy()、str n cat() 或 s n printf()。
超出缓冲区空间将丢弃内存中的任何其他内容!
(请记住为结尾的 null '\0' 字符留出空间!)
如果您事先不知道要连接多少个字符串,那么 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);
}
没有限制缓冲区大小的最佳方法是使用 asprintf()
char* concat(const char* str1, const char* str2)
{
char* result;
asprintf(&result, "%s%s", str1, str2);
return result;
}
尝试修改字符串文字是未定义的行为,类似于:
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.
如果您有 C 经验,您会注意到字符串只是最后一个字符为空字符的字符数组。
现在这很不方便,因为您必须找到最后一个字符才能附加一些东西。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 的特殊版本,它们为您分配缓冲区。不确保缓冲区大小将导致内存损坏和可远程利用的错误。
不要忘记初始化输出缓冲区。strcat 的第一个参数必须是一个以空结尾的字符串,并为结果字符串分配足够的额外空间:
char out[1024] = ""; // must be initialized
strcat( out, null_terminated_string );
// null_terminated_string has less than 1023 chars
正如人们指出的那样,字符串处理得到了很大改善。因此,您可能想学习如何使用 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 中执行此操作的更好方法。
strcat() 的第一个参数需要能够为连接的字符串保留足够的空间。所以分配一个有足够空间的缓冲区来接收结果。
char bigEnough[64] = "";
strcat(bigEnough, "TEXT");
strcat(bigEnough, foo);
/* and so on */
strcat() 会将第二个参数与第一个参数连接起来,并将结果存储在第一个参数中,返回的 char* 就是第一个参数,只是为了您的方便。
您没有得到连接第一个和第二个参数的新分配的字符串,我猜您根据您的代码预期。
您正在尝试将字符串复制到静态分配的地址中。您需要 cat 进入缓冲区。
具体来说:
……剪……
目的地
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
这里也有一个例子。
您可以编写自己的函数来做同样的事情,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
以满足您的需要。
尝试类似的事情:
#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;
}
假设你有一个 char[fixed_size] 而不是一个 char*,你可以使用一个单一的、创造性的宏来一次完成所有的<<cout<<like
排序(“而不是 %s 脱节的 %s\n”、“than”、“printf样式格式”)。如果您正在使用嵌入式系统,此方法还允许您省略 malloc 和大型*printf
函数系列,例如snprintf()
(这也使 Dietlibc 不会抱怨 *printf)
#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);
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;
}
这是我的解决方案
#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");