如何连接两个C样式(以null结尾)字符串?

如何连接两个C样式(以null结尾)字符串?,c,concatenation,null-terminated,C,Concatenation,Null Terminated,我想连接两个字符串,它们的定义如下: char hello[] = { 'H', 'e', 'l', 'l', 'o', '\0' }; char world[] = { ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0' }; void strcopycst(char* destination, char* source) { while((*destination++ = *source++)) ; } 我知道我应该遍历第一个字符串,

我想连接两个字符串,它们的定义如下:

char hello[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char world[] = { ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0' };
void strcopycst(char* destination, char* source)
{
    while((*destination++ = *source++))
    ;
}
我知道我应该遍历第一个字符串,找到
'\0'
符号,而不是第二个字符串。功能
strcat
是否以相同的方式工作

我正在使用的代码:

for (int i = 0; i < 6; i++) {
    if (hello[i] == '\0') {
        for (int j = 0; j < 9; j++) {
            int index = 5 + j;
            hello[index] = world[j];
        }
    }
}
for(int i=0;i<6;i++){
如果(hello[i]='\0'){
对于(int j=0;j<9;j++){
int指数=5+j;
你好[index]=world[j];
}
}
}
编译后我得到这样一个错误:

*检测到堆栈崩溃*:。/运行已终止


我做错了什么?

只会为
hello
分配六个字节的内存。因此,尝试为新连接的字符串创建新内存


请参阅strcat()实现。

仅为
hello
分配六个字节的内存。因此,尝试为新连接的字符串创建新内存


请参阅strcat()实现。

您不需要如此细致地定义字符串。这也适用于:

char hello[] = "Hello";
char world[] = ", World!";
C将为您处理这些问题

您还可以并行复制,一个常见的习惯用法是:

while(*destination++ = *source++)
    ;
这将首先将
source
当前指向
destination
的字符分配给
目标,然后增加两个指针(仅指针,而不是指针内部的内容)。这是因为解引用优先于增量。两个指针并行递增

例如,在while循环第一次运行后,
目标
都将指向内存中包含相同字符的地址

在某一点上,它们将计算为
\0
,而
循环的计算结果为
false
,它将停止复制它们(因为表达式将不再计算为
true

由于这(和strcat()
)被认为有点不安全,所以在执行此操作之前,请确保目标中有足够的空间。或者使用
strncat()
,您可以限制复制的时间(如果字符串不是以null结尾的,并且您让它“rip”可以说是没有限制的,那么可能会发生不好的事情)

您可以这样使用上面的选项:

char hello[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char world[] = { ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0' };
void strcopycst(char* destination, char* source)
{
    while((*destination++ = *source++))
    ;
}
主要是:

char dest [25];
char source = "Hello, World!";

strcopycst(dest, source);
编辑:正如一位评论员提到的,我没有正确地解决连接问题。根据上面的代码,这里是一个粗略的strcat函数:

void cstmstrcat(char* dest, char* source1, char* source2) /* dest must be big enough */
{
    while((*dest++ = *source1++))
        ;

    --dest; /* backtrack the pointer as after the above 
               it will point to some random memory value */

    while((*dest++ = *source2++))
        ;
}
下面是它的使用方法:

int main()
{
    char source1 [] = "Hello";
    char source2 [] = ", World!";
    char dest [50];

    cstmstrcat(dest, source1, source2);

    printf("%s\n", dest);

    return 0;
}

它打印“Hello,World!”。

您不需要如此细致地定义字符串。这也适用于:

char hello[] = "Hello";
char world[] = ", World!";
C将为您处理这些问题

您还可以并行复制,一个常见的习惯用法是:

while(*destination++ = *source++)
    ;
这将首先将
source
当前指向
destination
的字符分配给
目标,然后增加两个指针(仅指针,而不是指针内部的内容)。这是因为解引用优先于增量。两个指针并行递增

例如,在while循环第一次运行后,
目标
都将指向内存中包含相同字符的地址

在某一点上,它们将计算为
\0
,而
循环的计算结果为
false
,它将停止复制它们(因为表达式将不再计算为
true

由于这(和strcat()
)被认为有点不安全,所以在执行此操作之前,请确保目标中有足够的空间。或者使用
strncat()
,您可以限制复制的时间(如果字符串不是以null结尾的,并且您让它“rip”可以说是没有限制的,那么可能会发生不好的事情)

您可以这样使用上面的选项:

char hello[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char world[] = { ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0' };
void strcopycst(char* destination, char* source)
{
    while((*destination++ = *source++))
    ;
}
主要是:

char dest [25];
char source = "Hello, World!";

strcopycst(dest, source);
编辑:正如一位评论员提到的,我没有正确地解决连接问题。根据上面的代码,这里是一个粗略的strcat函数:

void cstmstrcat(char* dest, char* source1, char* source2) /* dest must be big enough */
{
    while((*dest++ = *source1++))
        ;

    --dest; /* backtrack the pointer as after the above 
               it will point to some random memory value */

    while((*dest++ = *source2++))
        ;
}
下面是它的使用方法:

int main()
{
    char source1 [] = "Hello";
    char source2 [] = ", World!";
    char dest [50];

    cstmstrcat(dest, source1, source2);

    printf("%s\n", dest);

    return 0;
}

它会打印“Hello,World!”。

您可以通过分配足够的内存来解决对数组的访问超出范围的问题

char hello[14] = "Hello";

您可以通过分配足够的内存来解决数组的访问越界问题

char hello[14] = "Hello";

我的答案最初不会集中在正确连接字符串上;相反,我们将尝试解决代码中的一些问题,并给出一些背景想法,这些想法可能有助于澄清如何在C中思考问题。然后我们将研究串接

在我们开始之前,先谈谈C字符串的结构 用C语言思考就像计算机一样(CPU、内存等);因此,对于在CPU上本机工作的数据类型,C具有字符(单字节)、短字符(双字节字)、长字符(4字节字)、整数、浮点和双字节,所有这些都是CPU本机可以理解的。以及创建这些东西的数组或指向这些类型存在的内存位置的指针的能力

那么我们如何创建一个字符串呢?我们要创建一个新类型吗

既然CPU不懂字符串,C。。。无论如何,它不是最原始的形式(C解析器没有与字符串关联的类型)

但是字符串是非常有用的,所以必须有一个合理的简单概念,即如果决定了字符串,它应该是什么

所有C字符串都是顺序内存中的一个字节,不包括NUL字符

NUL(发音类似nool)是我们为内存中值为0的字节指定的名称。在C语言中,这由
\0
表示。所以如果我写NUL,它的意思是字符
\0

注1:这与C NULL不同,C NULL是一个值为零的内存地址

注2:NUL当然不是值为48的字符零('0')

因此,任何作用于字符串的函数都会启动一个由char*(read char pointe)指向的内存位置
*p = 0;
char str[] = "Foofoo";
char str[20] = "Foofoo";
Disassembly of section .data:

0000000000000000 <str>:
   0:    48 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00     Foofoo..........
  10:    00 00 00 00                                         ....
  char foo[1000]; /* Lots of room */
#include <stdio.h>

char str1[100] = "Hello";
char str2[] = ", World!"; /* No need to make this big */

int main()
{
    char *p;
    char *q;

    printf("str1 (before concat): %s\n", str1);

    for (p = str1; *p != 0; p++) {
        /* Skip along to find the end */
    }

    for (q = str2; *q != 0; p++, q++ ) {
        *p = *q;
    }
    *p = 0; /* Set the last character to 0 */

    printf("str1 (after concat): %s\n", str1);

    return 0;
}
  gcc -c concat.c -o concat.o
  objdump -d concat.o
   0:    55                       push   %rbp
   1:    48 89 e5                 mov    %rsp,%rbp
   4:    48 83 ec 10              sub    $0x10,%rsp
   8:    be 00 00 00 00           mov    $0x0,%esi
   d:    bf 00 00 00 00           mov    $0x0,%edi
  12:    b8 00 00 00 00           mov    $0x0,%eax
  17:    e8 00 00 00 00           callq  1c <main+0x1c>
gcc -O3 -c concat.c  -o concat.o
objdump -S -s concat.o


concat.o:     File format elf64-x86-64

Contents of section .text:
 0000 803d0000 000000b8 00000000 740b6690  .=..........t.f.
 0010 4883c001 80380075 f70fb615 00000000  H....8.u........
 0020 84d2741d b9000000 000f1f80 00000000  ..t.............
 0030 4883c101 88104883 c0010fb6 1184d275  H.....H........u
 0040 efc60000 31c0c3                      ....1..
Contents of section .data:
 0000 48656c6c 6f000000 00000000 00000000  Hello...........
 0010 00000000 00000000 00000000 00000000  ................
 0020 00000000 00000000 00000000 00000000  ................
 0030 00000000 00000000 00000000 00000000  ................
 0040 00000000 00000000 00000000 00000000  ................
 0050 00000000 00000000 00000000 00000000  ................
 0060 00000000 2c20576f 726c6421 00        ...., World!.
Contents of section .comment:
 0000 00474343 3a202844 65626961 6e20342e  .GCC: (Debian 4.
 0010 342e352d 38292034 2e342e35 00        4.5-8) 4.4.5.
Contents of section .eh_frame:
 0000 14000000 00000000 017a5200 01781001  .........zR..x..
 0010 1b0c0708 90010000 14000000 1c000000  ................
 0020 00000000 47000000 00000000 00000000  ....G...........

Disassembly of section .text:

0000000000000000 <main>:
   0:    80 3d 00 00 00 00 00     cmpb   $0x0,0x0(%rip)        # 7 <main+0x7>
   7:    b8 00 00 00 00           mov    $0x0,%eax
   c:    74 0b                    je     19 <main+0x19>
   e:    66 90                    xchg   %ax,%ax
  10:    48 83 c0 01              add    $0x1,%rax
  14:    80 38 00                 cmpb   $0x0,(%rax)
  17:    75 f7                    jne    10 <main+0x10>
  19:    0f b6 15 00 00 00 00     movzbl 0x0(%rip),%edx        # 20 <main+0x20>
  20:    84 d2                    test   %dl,%dl
  22:    74 1d                    je     41 <main+0x41>
  24:    b9 00 00 00 00           mov    $0x0,%ecx
  29:    0f 1f 80 00 00 00 00     nopl   0x0(%rax)
  30:    48 83 c1 01              add    $0x1,%rcx
  34:    88 10                    mov    %dl,(%rax)
  36:    48 83 c0 01              add    $0x1,%rax
  3a:    0f b6 11                 movzbl (%rcx),%edx
  3d:    84 d2                    test   %dl,%dl
  3f:    75 ef                    jne    30 <main+0x30>
  41:    c6 00 00                 movb   $0x0,(%rax)
  44:    31 c0                    xor    %eax,%eax
  46:    c3                       retq
char hello[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
#include <stdio.h>
int main(void) {
    char hello[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
    printf("%zu\n", sizeof hello);
}
#include <stdio.h>
#include <string.h>
int main(void) {
    char hello[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
    char world[] = { ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0' };

    /* Don't forget to add 1 for NUL */
    char hello_world[strlen(hello) + strlen(world) + 1];

    strcpy(hello_world, hello);
    strcat(hello_world, world);
    puts(hello_world);
}