C语言 为什么我不能像这样将结构体成员值赋给字符串变量?

jutyujz0  于 2023-08-03  发布在  其他
关注(0)|答案(4)|浏览(119)
#include <stdio.h>
#include <string.h>

struct car {
    char make[10];
    char model[25];
    char type[10];
};

void main()
{
    struct car myCar;
    strcpy(myCar.make, "Nissan");
    strcpy(myCar.model, "Rogue");
    strcpy(myCar.type, "SUV");
    
    //char make[] = myCar.make;
    //char model[] = myCar.model;
    //char type[] = myCar.type;
}

字符集
我试图将myCar.make的值赋给make[]。为什么我不能直接将myCar.make的值赋给make[]?
注:我主要用java编程,那么这个问题和我对java的理解有关系吗?

6mzjoqzu

6mzjoqzu1#

考虑另一个同样不起作用的案例:

void foo() {
    char src[6] = "hello";
    char dst[] = src;
}

字符集
这里的情况与上面的代码相同,但更简单。
我同意,这 * 应该 * 工作。编译器 * 应该 * 能够指出src的大小为6(不要忘记空终止符)。所以dst * 的大小应该是6,赋值应该一个字符一个字符地复制。
然而,事实并非如此。你问我为什么。答案基本上是,当C被发明时,编译器的标准要低得多,所以除了一些特殊情况(比如当你首先定义src时),语言并不是这样工作的。我承认这可能不令人满意。
当你写上面的代码时,编译器基本上会看到:

char* src = /* ??? */;
char dst[] = src;


这种现象被称为“指针衰减”,更常见的情况是函数参数。希望你能明白为什么把指针复制到数组中不起作用:dst在堆栈上分配。编译器如何知道要提前分配多少堆栈空间?它不能;它必须等到运行时才能看到字符串src指向什么大小,到那时就太晚了。
现代编译器更好,他们意识到了这个问题:

<source>(3): error C2440: 'initializing': cannot convert from 'char []' to 'char []'
<source>(3): note: There are no conversions to array types, although there are conversions to references or pointers to arrays


简而言之,它理解src是一个数组,但60年代和70年代制定的语言规则不允许它推断大小。
另一种看待这一点的方式是,这种语言不够智能,无法理解更复杂的赋值。逐个字符赋值(strcpy的核心)实际上是一个不平凡的操作。C语言的规则是只能复制已知大小的东西,比如int s、指针和struct s。数组的大小不是它的类型的一部分,在C中,所以一个数组和另一个数组有不同的大小,不能赋值。
我用“in C”来限定所有这些,因为C仍然与历史上的原始语言非常相似。有些人认为这种简单是值得尊敬和可取的。其他人则认为这是毫无意义的限制--缺乏表现力,没有任何意义。
C++继承了C的规则,但也提供了std::string,它可以理解operator=(实际上在这种情况下是一个构造函数),足以复制:

#include <string>
void foo() {
    char src[6] = "hello";
    std::string dst = src; //Totally fine
}


当你得到dst的定义时,编译器仍然将src视为指针,但是std::string有一个理解指针的构造函数,并且会做正确的事情:用strlen发现指向的字符缓冲区的长度,动态分配新的内存来保存它,并逐个字符地复制它。
数组也可以定义为size is 是类型的一部分:

#include <array>
void foo() {
    std::array<char,6> src = /* ... */;
    std::array<char,6> dst = src; //Totally fine
}


当然,现在出于同样的原因,我们不能用"hello"初始化src。……

wgeznvg7

wgeznvg72#

我试图将myCar.make的值赋给make[]。为什么我不能直接将myCar.make的值赋给make[]?

char make[] = myCar.make;

字符集
这更好地称为“初始化”而不是“赋值”。虽然有相似之处,但C对 * 初始化 * 和 * 赋值 * 有不同的规则。初始化发生在对象被 * 定义 * 并**给定一个值时。
不幸的是,在这种情况下,arraymyCar.make首先被转换为第一个元素的类型和地址,因此代码如下所示:

char make[] = &(myCar.make[0]);


试图用指针初始化数组-这是没有意义的。
C没有提供一种通过简单的初始化来初始化数组(并确定其大小)的方法。
另一种方法是定义一个新数组,初始化或不初始化,然后 * 赋值 * 数组元素。

#define ARRAY_ELEMENT_COUNT(a)  (sizeof (a)/sizeof (a)[0])
char make[ARRAY_ELEMENT_COUNT(myCar.make)];

// Note : elements after the null character remain uninitialized.
strcpy(make, myCar.make);


一种更符合C语言习惯的方法涉及字符串管理。这可能比OP现在准备的更先进。

struct car {
  char *make;
  char *model;
  ...
};

int main(void) {
  struct car myCar;
  strcpy(myCar.make, "Nissan");
  strcpy(myCar.model, "Rogue");

  char *make = strdup(myCar.make);
  ...
  free(make);
}

qv7cva1a

qv7cva1a3#

在C中,你不能像使用常规变量那样直接用一个数组初始化另一个数组,因为数组在C中不是直接可赋值或可初始化的类型。
初始化发生在声明时,而赋值发生在声明变量之后。
当你声明一个像char make[]这样的数组时,编译器需要在编译时知道数组的大小,这样它才能分配正确的内存量。
当您尝试执行char make[] = myCar.make;你实际上是在用指针初始化数组。
赋值的右边(myCar.make)是一个表达式,没有与之关联的内存分配。
你必须一个元素一个元素地复制数组,这可以使用strcpy()这样的函数来完成。
以下是如何修改代码:

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

struct car {
    char make[10];
    char model[25];
    char type[10];
};

int main()
{
    struct car myCar;
    strcpy(myCar.make, "Nissan");
    strcpy(myCar.model, "Rogue");
    strcpy(myCar.type, "SUV");
    
    char make[10];
    char model[25];
    char type[10];
    
    strcpy(make, myCar.make);
    strcpy(model, myCar.model);
    strcpy(type, myCar.type);
    
    printf("Make: %s\n", make);
    printf("Model: %s\n", model);
    printf("Type: %s\n", type);

    return 0;
}

字符集
在这段代码中,为make、model和type声明了与car结构中的字符串大小相同的新字符串。
然后使用strcpy()将myCar.make、myCar.model和myCar.type的内容复制为make、model和type。

js5cn81o

js5cn81o4#

您正在尝试声明新的字符数组,并将myCar.make、myCar.model和myCar.type的值赋给它们,对吗?但有个问题在C中,数组(包括那些存储字符串的数组,也称为字符数组)比简单的数据类型要复杂一些。它们对赋值运算符(=)不友好。
所以,当你说char make[] = myCar.make;,C编译器听到的是“嘿,创建一个新数组,并将myCar.make的内容复制到其中!但是编译器说“不行,伙计。我并不适合只使用=来处理复制数组。对不起!”
相反,您必须使用类似strcpy()函数的东西,类似于您在为myCar.make、myCar.model和myCar. type赋值时所做的操作。

char make[10];
char model[25];
char type[10];

strcpy(make , myCar.make);
strcpy(model , myCar.model);
strcpy(type , myCar.type);

字符集
将make、model和type声明为具有适当大小的字符数组(与结构体中的大小相同),然后将相应结构体成员的内容复制到其中。
我的电脑不在我身边,我不能检查我的代码,这是真的很长一段时间,我没有用C程序。

相关问题