在函数中初始化char *类型的成员会引发警告并产生意外行为

时间:2015-10-19 20:43:20

标签: c gcc

我尝试创建一个函数来接收const char *变量来初始化结构的char *成员并返回所述结构。问题是我得到一个警告,说我正在转换整数指针。此外,当我尝试打印时,它并不像我预期的那样工作,尽管在函数外部初始化可以完美地工作。我使用没有标志的gcc来编译它。我制作了我的代码的最小版本,它给了我同样的警告:

#include <stdio.h>

struct Person {
    char name[128];
};

struct Person initialize_person(const char *name);

main() {
    /* raises warning: */
    struct Person person1;
    person1 = initialize_person("John Doe");

    /* does not raise a warning: */
    struct Person person2 = {"Mary Foo"};

    printf("person1: %s\n"  /* prints garbage */
           "person2: %s\n", /* prints what is expected */
           person1.name, person2.name);

    return 0;
}

struct Person initialize_person(const char *name)
{
    struct Person new_person = {name};
    /* I thought name would be equivalent to
       litterally "John Doe" here */

    return new_person;
}

它提出了这个警告:

main.c: In function ‘initialize_person’:
main.c:25:9: warning: initialization makes integer from pointer without a cast [enabled by default]
  struct Person new_person = {name};
         ^
main.c:25:9: warning: (near initialization for ‘new_person.name[0]’) [enabled by default]

3 个答案:

答案 0 :(得分:3)

这实际上与结构无关,而是与char数组有关。

char[]的初始值设定项不能是指向char的指针。它必须是字符串文字或可转换为char的值序列。

(寻求实际正式定义的帮助,如果有人的话。)

换句话说:

char foo[128] = "foo";

char foo[128] = {1, 2, 3};

问题是编译器需要一个常量表达式,因此它可以生成用这些值初始化结构的代码。关键是初始化程序的长度是已知的。使用您的代码尝试使用指针时,长度是未知的。

在我提出解决方案之前的一些建议:不要将值按结构传递给函数,也不要将它们从函数中返回。使用指向结构的指针要高效得多,因为结构不需要复制。

bool initialize_person(struct Person *person; const char *name)
{
    if (strlen(name) > sizeof(person->name - 1) {
        // Name is too long
        return false;
    }

    strcpy(person->name, name);
    return true;
}

int main(void)
{
    struct Person person1;

    if (!initialize_person(&person1, "John Doe")) {
        exit(1);
    }

    return 0;
}

答案 1 :(得分:3)

鉴于此声明:

struct Person {
    char name[128];
};

您不能像这样初始化struct Person

struct Person initialize_person(const char *name)
{
    struct Person new_person = {name};

字符串文字与char *(尽管有const nence)不同,与数组不是指针的方式非常相似。要从变量数据初始化struct成员char数组,您需要显式复制。这与您可能达到的目标一样接近:

    struct Person new_person;

    strncpy(new_person.name, name, sizeof(new_person.name) - 1);

但请注意,当您返回struct时,您将创建另一个副本。相反,请考虑将指针传递给要初始化的struct以及初始化数据,或者动态分配struct,初始化它,并返回指向结果的指针。

答案 2 :(得分:2)

问题在于new_person的初始化程序。

struct Person new_person = {name};

它不会将name指向的数组复制到数组new_person.name
相反,它做到了这一点:

struct Person new_person; new_person.name[0] = name;

所以它试图将指针复制到char,因此警告。 new_person.name[0]获取的值与您想要的值不同,并且数组的其余部分保持未初始化状态,因此会打印垃圾。

解决问题的方法不正确:

struct Person new_person =  
{name[0],name[1],name[2],name[3],name[4],name[5],name[6],name[7],name[8]};

你的程序会像那样正常工作。但只是因为&#34; John Doe&#34;和#34; Mary Foo&#34;最多8个字符。它会因较大的字符串而失败 解决问题的正确方法是:

struct Person new_person;
sprintf(new_person.name, "%.127s", name);

即使使用不符合名称的空间的字符串,这也能正常工作。它们将被剪切,只使用127个第一个字符。