我正在使用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方面的经验,我相信您会在尝试运行它时遇到分段错误。那么我该如何解决呢?
Answers:
在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
,并且在其中必须明确指定目标缓冲区的大小。
注意:字符串文字不能用作缓冲区,因为它是一个常量。因此,您始终必须为缓冲区分配一个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);
避免strcat
在C代码中使用。最干净,最重要的是最安全的方法是使用snprintf
:
char buf[256];
snprintf(buf, sizeof buf, "%s%s%s%s", str1, str2, str3, str4);
一些评论者提出了一个问题,即参数的数量可能与格式字符串不匹配,并且代码仍会编译,但是在这种情况下,大多数编译器已经发出警告。
snprintf()
是一个很大的否定。
sizeof(x)
和之间没有意义的区别sizeof x
。带括号的符号始终有效,非带括号的符号有时仅适用,因此请始终使用带括号的符号。这是要记住的简单规则,并且很安全。这引起了一种宗教争论-我曾参加过与反对者的讨论-但是“总是使用括号”的简单性胜过不使用括号的任何优点(当然是IMNSHO)。这是为了平衡。
亲朋好友,请使用str n cpy(),str n cat()或s n printf()。
超过缓冲区空间将浪费内存中的所有其他内容!
(请记住要留出空格以结尾的空“ \ 0”字符!)
strncpy()
。这不是的“更安全”版本strcpy()
。目标字符数组可能不必要地被多余的'\0'
字符填充,或者更糟的是,它可能会不加终止(即,不是字符串)。(它设计用于一个已经很少使用的数据结构,一个字符数组填充到零个或多个'\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);
}
num_words>INT_MAX
,也许你应该使用size_t
对i
不要忘记初始化输出缓冲区。strcat的第一个参数必须是一个以null终止的字符串,并为结果字符串分配足够的额外空间:
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中执行此操作的更好方法。
<string.h>
是C ++风格。你要"string.h"
。您还会计算strlen(s1)
两次,这是不需要的。 s3
应该很totalLenght+1
长。
"string.h"
废话。
#include <string.h>
是正确的C。对标准和系统标题(包括<string.h>
)使用尖括号,在程序的标题中使用引号引起来。(#include "string.h"
如果您没有该名称的头文件,但<string.h>
无论如何都可以使用。)
尝试修改字符串文字是未定义的行为,如下所示:
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.
最好的方法是在没有缓冲区大小限制的情况下使用asprintf()
char* concat(const char* str1, const char* str2)
{
char* result;
asprintf(&result, "%s%s", str1, str2);
return result;
}
char *
,没有const char *
。返回值将需要传递给free
。
asprintf
是,这只是一个GNU扩展。
如果您有使用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为您分配缓冲区。不确保缓冲区大小将导致内存损坏和可远程利用的错误。
"TEXT"
是char[5]
,没有 const char*
。char*
在大多数情况下,它都会衰减。出于向后兼容的原因,字符串文字不是const
,但是尝试对其进行修改将导致未定义的行为。(在C ++中,字符串文字为const
。)
您可以编写自己的函数,该函数执行的功能相同,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
以适合您的需求。
strlen(str1) + strlen(str2)
,但您写了strlen(str1) + strlen(str2) + 1
字符。那么,您真的可以编写自己的函数吗?
return buffer; free(buffer);
sizeof(char) == 1
(此外,还有其他更细微的错误...)您现在可以看到为什么不必编写自己的函数了吗?
free(buffer);
。
free(buffer);
之后return buffer;
永远不会执行,请在调试器中查看它;)我现在看到了:是的,您必须释放该main
函数中的内存
假设您使用的是char [fixed_size]而不是char *,则可以使用单个广告素材宏通过一次<<cout<<like
命令(“%s the相交的%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;
}
您正在尝试将字符串复制到静态分配的地址中。您需要注意缓冲区。
特别:
...剪...
目的地
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
这里也有一个例子。
这是我的解决方案
#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");
试试类似的东西:
#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;
}