如何在C中复制char数组?


77

在C中,我有两个char数组:

char array1[18] = "abcdefg";
char array2[18];

如何复制的价值array1array2?我可以这样做array2 = array1吗?


3
strcpymemcpy
Alok保存

1
char array1[18] = {"abcdefg"};不是正确的char数组。
aragaer

使用strcpy(array2,array1)函数
Rohan

1
虽然它确实可以作为char数组工作(恰好可以工作),但是应该声明为char array1[18] = "abcdefg";char array1[18] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', '\0'};
aragaer

13
@aragaer 6.7.9(14):“字符类型的数组可以用字符串文字或UTF-8字符串文字初始化,可以选择用大括号括起来。” char array1[18] = {"abcdefg"};是不寻常的,但100%的pukka。
丹尼尔·菲舍尔

Answers:


82

您无法直接执行操作array2 = array1,因为在这种情况下,您需要操纵数组(char *)而不是其内部值(char)的地址。

从概念上讲,您想要做的是遍历源代码(array1)的所有字符并将它们复制到目标(array2)。有几种方法可以做到这一点。例如,您可以编写一个简单的for循环,或使用memcpy

话虽这么说,推荐的字符串方式是使用strncpy。它可以防止常见的错误,例如,导致缓冲区溢出(如果array1从用户输入(键盘,网络等)填充缓冲区,这尤其危险)。像这样:

// Will copy 18 characters from array1 to array2
strncpy(array2, array1, 18);

作为@教授。法肯在评论中提到,strncpy 可能是邪恶的。确保目标缓冲区足够大以包含源缓冲区(包括\0字符串末尾的)。



为什么我们不能只做array2 = array1?
user2131316

2
@ user2131316:这是因为数组名在语义上转换为指针值的方式。我在回答中对此进行了解释。
jxh

您提到了我,这使我感到困惑array1=array2,这意味着array1获得了新值,但是您的代码却以相反的方式做到了。以防万一有人落入这个。
lucidbrot

33

如果您的数组不是字符串数组,请使用: memcpy(array2, array1, sizeof(array2));


19
memcpy的第一个参数是目标数组,应为array2!
Bert Regelink 2015年

sizeof()是否不会返回指针的大小(即计算机上的字大小)?
Wecherowski

1
@Wecherowski:将数组传递给函数时,它会降级为指针。在该函数中,您不能sizeof()用来确定数组的大小。否则,sizeof()可以很好地完成该任务。
Bugfinger

26

如果要防止可能导致各种问题的非终止字符串,请按以下方式复制您的字符串:

char array1[18] = {"abcdefg"};
char array2[18];

size_t destination_size = sizeof (array2);

strncpy(array2, array1, destination_size);
array2[destination_size - 1] = '\0';

最后一行实际上很重要,因为strncpy()并不总是将null终止字符串。(如果目标缓冲区太小而无法包含整个源字符串,则sntrcpy()不会将null终止目标字符串。)

strncpy()的联机帮助页甚至指出“警告:如果src的前n个字节中没有空字节,则放置在dest中的字符串将不会以空值结尾。”

之所以用strncpy()来表现这种奇怪的方式,是因为实际上它最初并不是要用作复制字符串的安全方式。

另一种方法是使用snprintf()作为strcpy()的安全替代品:

snprintf(array2, destination_size, "%s", array1);

(感谢jxh的提示。)


2
注意snprintf()没有那个问题strncpy()
jxh

这不会产生警告吗?strncpy接受const char作为源。
kon psych

@konpsych,不应产生警告。
Falken教授

6

您不能分配数组,名称是不能更改的常量。

您可以使用以下命令复制内容

strcpy(array2, array1);

假设源是有效字符串,并且目标足够大,如您的示例所示。


5

正如其他人指出的那样,字符串是使用strcpy()或其变体复制的。在某些情况下,您也可以使用snprintf()

您只能以所需的方式分配数组作为结构分配的一部分:

typedef struct { char a[18]; } array;
array array1 = { "abcdefg" };
array array2;

array2 = array1;

如果将数组传递给函数,则似乎可以分配它们,但这只是语义上的偶然。在C语言中,数组将使用数组第一个成员的地址值衰减为指针类型,并且该指针将被传递。因此,函数中的数组参数实际上只是一个指针。该分配只是一个指针分配:

void foo (char x[10], char y[10]) {
    x = y;    /* pointer assignment! */
    puts(x);
}

从函数返回后,数组本身保持不变。

数组的这种“指向指针值的衰减”语义是分配无效的原因。l值具有数组类型,但r值是衰减的指针类型,因此分配在不兼容的类型之间进行。

char array1[18] = "abcdefg";
char array2[18];
array2 = array1; /* fails because array1 becomes a pointer type,
                    but array2 is still an array type */

至于为什么引入“拒绝指针值”语义,这是为了实现与C的前身的源代码兼容性。有关详细信息,请阅读《 C语言的发展》


唯一的答案可以解释为什么array2 = array1;不起作用。赞成。
米尔詹·米基奇

3

它应该看起来像这样:

void cstringcpy(char *src, char * dest)
{
    while (*src) {
        *(dest++) = *(src++);
    }
    *dest = '\0';
}
.....

char src[6] = "Hello";
char dest[6];
cstringcpy(src, dest);

1
您的cstringcpy函数不会将null终止目标数组。
chqrlie

没有得到它。请提供您的“修正”。
鲍里斯(Boris)

@ zett42:请注意,此cstringcpy函数在语义上几乎完全等同于strcpy,具有相同的缺点,即不检查缓冲区溢出。
chqrlie

2

我建议使用memcpy()复制数据。另外,如果我们将缓冲区分配给as array2 = array1,则两个数组都具有相同的内存,并且arrary1中的任何更改也会在array2中发生偏移。但是我们使用memcpy,两个缓冲区都有不同的数组。我建议使用memcpy(),因为strcpy和相关函数不会复制NULL字符。



1

仅在下面的c函数... c ++,您必须执行char数组操作,然后使用字符串副本,然后使用字符串tokenizor函数... c ++使很多操作变得更加困难

#include <iostream>
#include <fstream>
#include <cstring>
#define TRUE 1
#define FALSE 0
typedef int Bool;
using namespace std;
Bool PalTrueFalse(char str[]);
int main(void)
{
char string[1000], ch;
int i = 0;
cout<<"Enter a message: ";

while((ch = getchar()) != '\n') //grab users input string untill 
{                               //Enter is pressed
    if (!isspace(ch) && !ispunct(ch)) //Cstring functions checking for
    {                                //spaces and punctuations of all kinds
        string[i] = tolower(ch); 
        i++;
    }
}
string[i] = '\0';  //hitting null deliminator once users input
cout<<"Your string: "<<string<<endl; 
if(PalTrueFalse(string)) //the string[i] user input is passed after
                        //being cleaned into the null function.
    cout<<"is a "<<"Palindrome\n"<<endl;
else
   cout<<"Not a palindrome\n"<<endl;
return 0;
}

Bool PalTrueFalse(char str[])
{
int left = 0;
int right = strlen(str)-1;
while (left<right)
{
   if(str[left] != str[right]) //comparing most outer values of string
       return FALSE;          //to inner values.
   left++;
   right--;
}
return TRUE;
}

0

对于整数类型

#include <string.h>    

int array1[10] = {0,1,2,3,4,5,6,7,8,9};
int array2[10];


memcpy(array2,array1,sizeof(array1)); // memcpy("destination","source","size")

1
那不会编译。使用int array1[10] = {0,1,2,3,4,5,6,7,8,9};代替。
蒂姆(Tim)

0

您不能分配数组来复制它们。如何将一个内容复制到另一个内容取决于多种因素:

对于char数组,如果您知道源数组以null终止,并且目标数组对于源数组中的字符串(包括null终止符)足够大,请使用strcpy()

#include <string.h>

char array1[18] = "abcdefg";
char array2[18];

...

strcpy(array2, array1);

如果您不知道目标数组是否足够大,但是源数组是C字符串,并且希望目标数组是正确的C字符串,请使用snprinf()

#include <stdio.h>

char array1[] = "a longer string that might not fit";
char array2[18];

...

snprintf(array2, sizeof array2, "%s", array1);

如果源数组不一定以null结尾,但是您知道两个数组的大小相同,则可以使用memcpy

#include <string.h>

char array1[28] = "a non null terminated string";
char array2[28];

...

memcpy(array2, array1, sizeof array2);

0

好吧,技术上您可以…

typedef struct { char xx[18]; } arr_wrap;

char array1[18] = "abcdefg";
char array2[18];

*((arr_wrap *) array2) = *((arr_wrap *) array1);

printf("%s\n", array2);     /* "abcdefg" */

但看起来不会很漂亮。

…除非您使用C预处理器…

#define CC_MEMCPY(DESTARR, SRCARR, ARRSIZE) \
    { struct _tmparrwrap_ { char xx[ARRSIZE]; }; *((struct _tmparrwrap_ *) DESTARR) = *((struct _tmparrwrap_ *) SRCARR); }

然后,您可以执行以下操作:

char array1[18] = "abcdefg";
char array2[18];

CC_MEMCPY(array2, array1, sizeof(array1));

printf("%s\n", array2);     /* "abcdefg" */

而且它将适用于任何数据类型,而不仅仅是char

int numbers1[3] = { 1, 2, 3 };
int numbers2[3];

CC_MEMCPY(numbers2, numbers1, sizeof(numbers1));

printf("%d - %d - %d\n", numbers2[0], numbers2[1], numbers2[2]);     /* "abcdefg" */

(是的,上面的代码被授予可以一直工作并且可移植)


0

以上都不对我有用..这name在这里完美工作 char *name是通过函数传递的

  1. 获得char *name使用时间strlen(name)
  2. 将其存储在const变量中很重要
  3. 创建相同长度的char数组
  4. 复制name的内容temp使用strcpy(temp, name);

如果您想返回原始内容,请随意使用。strcpy(name, temp);将温度复制回去name,瞧,效果很好

    const int size = strlen(name);
    char temp[size];
    cout << size << endl;
    strcpy(temp, name);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.