【问题标题】:Two dimensional array with char pointer in cc中带有char指针的二维数组
【发布时间】:2019-04-11 09:52:50
【问题描述】:

在下面的代码中,我尝试为每个乐队获取乐队成员的数量。我已经尝试了很多东西,但没有任何效果。以下看起来应该但不是。

如果有人能指出我做错了什么,将不胜感激。

numMembers = sizeof(bands[0]) / sizeof(bands[0].members);

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

int main(void) {
    int         i;  
    int         j;  
    int         numBands;
    int         numMembers;
    int         limit = 4;

    struct band {
        char        name[10];
        char        *members[20];
    };  

    const struct band bands[] =
        {   {"Beatles", {"John", "George", "Paul", "Ringo", "Pete", "George"} },
            {"Stones",  {"Mick", "Keith", "Bill", "Charlie", "Brian"} },
            {"Who",     {"Pete", "Roger", "Keith", "John"} },
            {"JHE",     {"Jimmy", "Noel", "Mitch"} }  };  

    numBands   = sizeof(bands) / sizeof(bands[0]);

    for ( i = 0; i < numBands; ++i ) { 
        printf ("%s\n", bands[i].name);
        numMembers = sizeof(bands[0]) / sizeof(bands[0].members);
        for ( j = 0; j < numMembers; ++j )
            printf ("\t%s", bands[i].members[j]);
        printf ("\n");
    }   

    return 0;
}

【问题讨论】:

  • 设计问题:为什么对乐队名称使用固定数组大小char name[10],而对乐队成员使用字符指针?我希望像 char *name; char *members[20];char name[10]; char members[20][30];
  • 第一行是语法错误

标签: c arrays pointers struct char


【解决方案1】:

您没有“二维数组”。您所拥有的是一个简单的 数组 struct band,其中包含两个简单的字符数组作为其成员。

实际上不需要计算每个波段中"members" 的数量。您只需要计算bands 的数量,例如

    int nbands = sizeof bands / sizeof *bands;

由于您已将 members 声明为 指针数组 并使用初始化程序来初始化前四个,因此其余指针将设置所有字节 0 导致每个字节为 @987654329 @。您可以简单地用while (bands[i].members[j]) 循环members,每次迭代递增j,例如

#include <stdio.h>

struct band {
    char    name[10];
    char    *members[20];
};

int main(void) {

    const struct band bands[] = {
        {"Beatles", {"John", "George", "Paul", "Ringo", "Pete", "George"} },
        {"Stones",  {"Mick", "Keith", "Bill", "Charlie", "Brian"} },
        {"Who",     {"Pete", "Roger", "Keith", "John"} },
        {"JHE",     {"Jimmy", "Noel", "Mitch"} } };  

    int nbands = sizeof bands / sizeof *bands;

    for (int i = 0; i < nbands; i++) {
        int j = 0;
        puts (bands[i].name);
        while (j < 20 && bands[i].members[j])
            printf (" %s", bands[i].members[j++]);
        putchar ('\n');
    }
}

(note 添加j &lt; 20,正如@chux 在 cmets 中指出的那样,单独测试while (bands[i].members[j]) 可能会导致在添加额外带的情况下出现未定义行为bands 初始化后和 members 结构成员的所有 20 指针都被填充)

使用/输出示例

$ ./bin/bandmembers
Beatles
 John George Paul Ringo Pete George
Stones
 Mick Keith Bill Charlie Brian
Who
 Pete Roger Keith John
JHE
 Jimmy Noel Mitch

此外,不要在代码中使用幻数。相反,如果您需要一个常量,#define 一个(或多个),例如

#define MAXNM 10
#define MAXMB 20

或使用全局enum 来做同样的事情,例如

enum { MAXNM = 10, MAXMB = 20 };

这将允许您消除 幻数,例如

struct band {
    char    name[MAXNM];
    char    *members[MAXMB];
};

随着代码长度的增加,这对于可维护性变得非常重要。

【讨论】:

  • while (bands[i].members[j]) printf (" %s", bands[i].members[j++]); 这是初始化有 20 个乐队成员时的 UB。也许while (j &lt; MAXMB &amp;&amp; bands[i].members[j])
  • 我不认为MAXNMMAXNB 改进了代码。数字在其原始上下文中的含义很明显,使用sizeof 避免了由于代码重复而导致错误的可能性
  • @chux 虽然检查j &lt; MAXMB 是一个很好的补充,但它的检查是while (bands[i].members[j] != NULL),它不是基于初始化规则的UB。见§ 6.7.9 Initialization (p10)§ 6.7.9 Initialization (p19)
  • @M.M 同意这个简短的 sn-p。添加是为了解决“代码长度增长”的未来编程问题。我试图解决所有问题以及可能成为坏习惯的问题。有时,对退伍军人来说显而易见的信息对刚学习的人来说是有用的信息。
  • @chux - 是的,我明白你的意思,如果所有 20 名乐队成员后来都被填满,那么 UB。 (但编写的代码中没有UB)
【解决方案2】:

我做错了什么

numMembers 计算错误

numMembers 应该是数组中元素的数量。 (20)

每个bands[i].member 有20 个元素给定char *members[20]。几个元素填充了指向字符串文字的指针。大多数元素保持为 0 (NULL)。

// numMembers = sizeof(bands[0]) / sizeof(bands[0].members);
numMembers    = sizeof(bands[0].members) / sizeof(bands[0].members[0]);

尝试将NULL 打印为字符串

bands[i].members[j]NULL 时,printf ("\t%s", bands[i].members[j]); 无效。

并非所有bands[i].members[j] 都设置为非NULL 值。

numBands = sizeof(bands) / sizeof(bands[0]);

for ( i = 0; i < numBands; ++i ) { 
  printf ("%s\n", bands[i].name);
  numMembers = sizeof(bands[i].members) / sizeof(bands[i].members[0]);

  for ( j = 0; j < numMembers; ++j ) {
    if (bands[i].members[j]) {
      printf ("\t%s", bands[i].members[j]);
    } 
  }

  printf ("\n");
  }
} 

深入:

const struct band bands[] = { {"Beatles", ... 形式 bands 和大小 bands[] 基于初始化器的数量。

char *members[20]; 是一个固定大小,即使初始化没有提供 20 个字符串。第一个元素members[20] 按列表初始化,其余元素的指针值为0。

【讨论】:

    【解决方案3】:

    对于 numMembers = sizeof(bands[0]) / sizeof(bands[0].members);

    sizeofband(bands[0]) 将给出一个波段结构的大小——即名称的 10 个字节,然后是 20 * 指针的大小。

    sizeof(bands[0].members);将给出 20*thesizeof 一个指针

    不是你想要的,因为 sizeof 没有考虑指针指向的内容。

    它也没有考虑到其中一些成员指针将为 NULL,因此您不想计算它们。

    也许做得更好:

    for ( j = 0; j < 20 &&  bands[i].members[j] != NULL; ++j )
            printf ("\t%s", bands[i].members[j]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-30
      • 2016-06-23
      • 1970-01-01
      • 2017-04-26
      • 1970-01-01
      相关资源
      最近更新 更多