【问题标题】:C Programming: error: assignment to expression with array typeC 编程:错误:赋值给数组类型的表达式
【发布时间】:2020-05-15 20:22:04
【问题描述】:

您好,我是 C 的初学者,当我遇到这个问题时,我正在使用结构:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    char nom[20];
    char prenom[20];
    int note;
} Etu;

int main() {
    Etu E[5];
    E[0].nom = "reda";
    printf("%s", E[0].nom);
    return 0;
}

有了这个我有这个错误(error: assignment to expression with array type)。所以我决定用指针来做,它实际上是我使用的代码:

#include <stdio.h>
#include <stdlib.h>
typedef struct {
    char *nom;
    char *prenom;
    int note;
} Etu;

int main() {
    Etu E[5];
    E[0].nom = "reda";
    printf("%s", E[0].nom);
    return 0;
}

所以问题是它们之间有什么区别,因为字符串是指针。 谢谢你..

【问题讨论】:

标签: c


【解决方案1】:

字符串不是指针,它们是以空字节结尾的字符序列。这些序列存储在数组中,它们也不是指针,而是存在于内存中并且指针可以指向的对象。指针是一个变量,它包含一个对象在内存中的地址。

在第一个示例中,您尝试使用= 将字符串存储到数组中。 C 不支持这种类型的赋值,并且会显示明确的错误消息。您可以使用strcpy 将字符串复制到数组中,假设目标数组足够大以存储字符串的字节,包括空终止符。 "reda" 使用 5 个字节,所以复制到 E[0].nom 中就可以了:

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

typedef struct {
    char nom[20];
    char prenom[20];
    int note;
} Etu;

int main() {
    Etu E[5];
    strcpy(E[0].nom, "reda");
    printf("%s\n", E[0].nom);
    return 0;
}

第二个示例使用不同的方法:nom 现在定义为指向char 的指针。在main 中定义数组E 使其未初始化,因此您只能在将指针的值设置为指向内存中某处的char 的实际数组后才能读取指针。 E[0].nom = "reda"; 就是这样做的:将字符串文字"reda" 的地址设置为E[0] 的成员nom。编译器会将字符串文字放入它自己的数组中,包括一个空终止符,并且程序不得更改。

【讨论】:

  • 非常感谢。我还有另一个问题:如果我们使用 scanf("%s",E[0].nom) 它确实可以正常工作,即使我们不使用 nom 作为指针而只是作为字符数组
  • @RedaElIdrissi:为了避免缓冲区溢出,你应该写scanf("%19s", E[0].nom)
  • @RedaElIdrissi:它之所以有效,是因为当您将数组传递给函数时,该函数会收到指向数组第一个元素的指针。
【解决方案2】:

第一部分,你尝试复制两个字符数组(字符串不是指针,它是由空字符\0终止的字符数组)。

如果要将数组的值复制到另一个数组,可以使用memcpy,但对于字符串,也可以使用strcpy

 E[0].nom = "reda";

改为:

strcpy(E[0].nom,"reda");

第二部分,你让指针指向字符串文字。指针指向字符串的第一个字符(本例中为r)。

你可以看到How to copy a string using a pointer

还有Assigning strings to pointer in C Language

【讨论】:

    【解决方案3】:

    其实是一个低级的概念。

    如果我们说char nom[20],那么它的内存位置将在编译时决定,它将使用堆栈内存(请参阅堆栈内存和堆内存之间的区别以更好地掌握爱好者级编程)。所以我们需要将它与索引一起使用。

    比如,

    nom[0] = 'a';
    nom[1] = 'b'; // and so on.
    

    另一方面,如果我们使用双引号方法(或使用指针的第二种方法)创建字符串。双引号字符串被编译器标识为const char*,并且该字符串被放置在堆内存而不是堆栈内存中。而且它们的内存位置不是在编译时决定的。

    测试这两种类型字符串之间差异的一种非常有效的方法是,当您将sizeof()char[20] nom 一起使用时,它将返回20 * sizeof(char),毫无疑问,它的计算结果为20。它明确指出,无论您只使用 5 个字符还是 2 个字符,它都将始终占用 20 个字符的空间(在堆栈内存中)

    但在const char* 的情况下,如果您在此变量上使用 sizeof 运算符,它将返回取决于硬件的指针变量的大小(32 位将有 4 字节指针)和(64 位将有 8 字节指针)。因此,sizeof 运算符不显示指针中存储了多少个字符。它只显示指针的大小。但是使用const char* 的好处是,仅在存储 4 个字符时才占用所需的内存,而不是占用 5 个字节的内存(如果是字符串,则额外添加最后一个字节),如果是 8 个字符,它将占用 9 个字节依此类推,但请注意字符将存储在堆(内存)中

     pointer --------------------> "characters"
     (on stack)                       (heap)
    

    您在第一个问题中所做的是将仅存储在堆上的字符串分配给仅存储在堆栈上的数据类型。这不是字符串的问题。这是内存模型的问题

    希望你能理解。我不能我可以在 cmets 中详细说明。

    附加信息。堆栈内存比堆内存更快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-29
      • 1970-01-01
      • 2021-12-11
      • 2020-12-20
      • 2017-06-12
      • 2015-12-01
      相关资源
      最近更新 更多