【问题标题】:Structs 'const char *x' vs 'char x[30]'结构 'const char *x' 与 'char x[30]'
【发布时间】:2017-01-12 12:32:06
【问题描述】:

您好,抱歉,我在这段代码上停留了一段时间,但两者似乎都可以工作,我只是不太了解其中的区别。

struct faveThings{

  const char *favFood; 
  const char *faveFriend;


};

struct dog{

 const char name[20];
 const char breed[20];
 int height;
 int weight;

 struct faveThings dogFaves;

};

我可以完全理解 dog struct 使用 'char name[20]' 对我来说完全有意义。但是对于faveThings,我与'char *favFood'斗争,我知道这是一个指针,但是如果它只是一个字符,它怎么能保存一个字符串?它不应该是一个字符数组吗?

const char *favFood[20];

感谢您提供的任何帮助,我一直在努力寻找不同之处。

【问题讨论】:

    标签: c struct


    【解决方案1】:

    favFood 不包含字符串。它指向某个地方。并且可以使它指向一个字符,该字符是 in 字符串中的第一个字符。按照惯例,由于 c 字符串可以有不同的长度,它们以'\0' 字符结尾。这样,即使你只有一个指向第一个字符的指针,你也可以找到字符串的结尾。

    因此,像strlen 这样的库函数将使用指针从第一个字符指向每个后续字符,直到找到 NUL 字符。

    const char *favFood[20]; 是完全不同的野兽。这是一个包含 20 个指针的数组。每个指针都可以指向不同的东西。

    【讨论】:

    • 我知道它指向某个地方,但我不明白如何使用它来检索字符串,例如我可以用它来保存“Meat”并用 'theDog.dogFaves 返回它.favFood',这不应该只返回一个字符'M'而不是字符串吗?
    • @MGordon0405 - theDog.dogFaves.favFood 不返回任何内容。它计算字符串中第一个字符的地址,而不是字符本身。
    • @MGordon0405 - 暂时忘记字符串。你明白为什么只需要传递一个整数数组给一个函数、一个指向第一个元素的指针和数组长度吗?
    • @MGordon0405 - 是的,你掌握了它。然而,对于字符串,终止 NUL 约定已经到位,以避免必须在所有地方传递长度。这样,一个简单的指针就足以表示一个字符串
    • @StoryTeller 很好的解释,尤其是在 cmets 中。
    【解决方案2】:

    你说得对,const char *favFood; 确实指向单个char,但可以理解的是,会有一块内存包含连续的chars,并且该指针指向第一个。因此代码可以使用该指针访问块中的所有chars。

    使用favFood 的代码还将涉及执行内存分配,用字符(和空终止符)填充该内存,并看到favFood 指向该分配。

    const char *favFood[20]; 将是一个包含 20 个指针的数组。

    【讨论】:

    • 嗯,好的,谢谢你说得有道理。感谢您的帮助!
    【解决方案3】:

    下面是一个常量字符数组。它实际上包含五个元素,因为 C 语言在由" 符号分隔的字符串末尾添加了一个'\0'。在C中,一个数组对象,比如MEAT,实际上是指向数组第一个元素的指针,所以MEAT实际上是一个内存地址而不是整个字符数组!

    const char[] MEAT = "Meat";
    

    下面是指向const char 的指针。 * 符号告诉您它是一个指针。 (无论是按指向的类型还是按变量的名称放置星号都没有关系。这可能会造成混淆,因此我通常将类型信息放在一起并拥有自己的名称,但我相信这一点这不是最常用的约定。)favFood 变量使用MEAT 数组中的第一个字符的地址进行初始化。 (记住MEAT是一个内存地址,所以这是设置一个内存地址等于另一个。)

    const char* favFood = MEAT;
    

    在未来的某个时候,您的动物可能会突然决定不再喜欢肉,而现在它实际上更喜欢饼干(我知道,猫比狗更容易改变主意,但这只是一个例子)。

    const char BISCUITS[] = "Biscuits";
    
    /* Some code is done here, until you find... */
    
    favFood = BISCUITS;
    

    现在,MEATBISCUITS 都是常量,这意味着您无法更改它们,但 favFood 本身不是常量,而是指向常量字符串(无论如何是字符串中的第一个字符),所以您可以改变它!

    你也可以有非常量字符串:

    char nameAndFaveFood[50];
    sprintf(nameAndFaveFood, "%.26s likes %.9s best.", name, favFood);
    

    ... 但请确保您复制的字符(包括终止的 '\0' 空字符)不超过分配的空间,在本例中为 49 个字符和一个终止符。这就是为什么sprint 函数有精确说明符来限制子字符串的长度。

    你可以拥有指向可变内存的常量指针。

    char* const LIKES_FOOD = &nameAndFaveFood[27];
    

    注意LIKES_FOOD 对象被初始化为指向nameAndFaveFood 数组的一部分。它总是指向那个地址。您可以使用不同的namefavFood 参数调用上一个代码块中的例程,但LIKES_FOOD 将始终指向nameAndFaveFood 数组中的第28 个字符。

    【讨论】:

      【解决方案4】:

      const char *favFood[20] 是一个指向字符数据的指针数组。

      好像

      *favFood[1] -------->MemLocation(0x001) = a
      *favFood[2] -------->MemLocation(0x002) = b
      

      等等请看这里:Can I create an Array of Char pointers in C?

      希望能回答你的问题

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-29
        • 1970-01-01
        • 2011-07-20
        • 1970-01-01
        • 1970-01-01
        • 2013-07-29
        • 1970-01-01
        相关资源
        最近更新 更多