58

我试图了解如何以最干净/最安全的方式在 C 中解决这个微不足道的问题。这是我的例子:

#include <stdio.h>

int main(int argc, char *argv[])
{
    typedef struct
    {
        char name[20];
        char surname[20];
        int unsigned age;
    } person;

    // Here I can pass strings as values...how does it work?
    person p = {"John", "Doe", 30};

    printf("Name: %s; Age: %d\n", p.name, p.age);

    // This works as expected...
    p.age = 25;

    //...but the same approach doesn't work with a string
    p.name = "Jane";

    printf("Name: %s; Age: %d\n", p.name, p.age);

    return 1;
}

编译器的错误是:

main.c:在函数'main'中:main.c:18:错误:从类型'char *'分配给类型'char [20]'时类型不兼容</p>

我知道 C(不是 C++)没有 String 类型,而是使用chars 的数组,所以另一种方法是更改​​示例结构以保存chars 的指针:

#include <stdio.h>

int main(int argc, char *argv[])
{
    typedef struct
    {
        char *name;
        char *surname;
        int unsigned age;
    } person;

    person p = {"John", "Doe", 30};

    printf("Name: %s; Age: %d\n", p.name, p.age);

    p.age = 25;

    p.name = "Jane";

    printf("Name: %s; Age: %d\n", p.name, p.age);

    return 1;
}

这按预期工作,但我想知道是否有更好的方法来做到这一点。

4

3 回答 3

58

第一个示例不起作用,因为您无法为数组分配值-在这方面,数组的工作(有点)像 const 指针。您可以做的是将一个新值复制到数组中:

strcpy(p.name, "Jane");

如果您事先知道字符串的最大大小,则可以使用 Char 数组,例如,在第一个示例中,您 100% 确定名称将适合 19 个字符(不是 20 个,因为总是需要一个字符来存储终止零价值)。

相反,如果您不知道字符串的最大可能大小,和/或您想优化内存使用,例如避免为名称“John”保留 512 个字符,则指针会更好。但是,对于指针,您需要动态分配它们指向的缓冲区,并在不再需要时释放它,以避免内存泄漏。

更新:动态分配缓冲区的示例(使用第二个示例中的结构定义):

char* firstName = "Johnnie";
char* surname = "B. Goode";
person p;

p.name = malloc(strlen(firstName) + 1);
p.surname = malloc(strlen(surname) + 1);

p.age = 25;
strcpy(p.name, firstName);
strcpy(p.surname, surname);

printf("Name: %s; Age: %d\n",p.name,p.age);

free(p.surname);
free(p.name);
于 2010-06-28T09:41:48.297 回答
11

将字符串视为抽象对象,将字符数组视为容器。字符串可以是任意大小,但容器必须至少比字符串长度大 1(以保存空终止符)。

C 对字符串的语法支持很少。没有字符串运算符(只有字符数组和字符指针运算符)。您不能分配字符串。

但是你可以调用函数来帮助实现你想要的。

strncpy()功能可以在这里使用。为了最大程度的安全,我建议遵循以下模式:

strncpy(p.name, "Jane", 19);
p.name[19] = '\0'; //add null terminator just in case

也看看strncat()memcpy()功能。

于 2010-06-28T09:45:14.293 回答
6

这两个结构是不同的。初始化第一个结构时,分配了大约 40 字节的内存。初始化第二个结构时,分配了大约 10 个字节的内存。(实际数量取决于架构)

您可以使用字符串文字(字符串常量)来初始化字符数组。这就是为什么

人 p = {“约翰”,“能源部”,30};

在第一个示例中有效。

您不能(在传统意义上)在 C 中分配字符串。

当您的代码执行时,您拥有的字符串文字(“John”)会加载到内存中。当您使用这些文字之一初始化数组时,该字符串将被复制到新的内存位置。在第二个示例中,您只是将指针复制到字符串文字(位置)。做类似的事情:

char* string = "Hello";
*string = 'C'

可能会导致编译或运行时错误(我不确定。)这是一个坏主意,因为您正在修改文字字符串“Hello”,例如在微控制器上,它可能位于只读内存中。

于 2010-06-28T09:50:21.527 回答