Двумерный массив с указателем на символ в c - PullRequest
0 голосов
/ 08 ноября 2018

В следующем коде я пытаюсь для каждой группы узнать количество участников группы. Я попробовал несколько вещей, но ничего не работает. Следующее выглядит так, как должно, но не так.

Если кто-нибудь и укажет на то, что я делаю неправильно, это будет с благодарностью.

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;
}

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

что я делаю не так

Неверно 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 в виде строки

printf ("\t%s", bands[i].members[j]); недействительно, если bands[i].members[j] равно NULL.

Не все 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.

0 голосов
/ 08 ноября 2018

У вас нет "двумерного массива". У вас есть простой массив struct band, который содержит два простых символьных массива в качестве своих членов.

Нет необходимости вычислять количество "members" в каждой полосе. Все, что вам нужно для вычисления, это число bands, например

    int nbands = sizeof bands / sizeof *bands;

Поскольку вы объявили members как массив указателей и использовали инициализатор для инициализации первых четырех, оставшиеся указатели будут иметь все установленные байты 0, в результате чего каждое будет NULL , Вы можете просто выполнить цикл для members с while (bands[i].members[j]), увеличивая 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 < 20, которое, как указал @chux в комментариях, только тест while (bands[i].members[j]) может привести к неопределенному поведению в случае добавления дополнительных полос bands после инициализации и все 20 указатели члена members struct были заполнены)

Пример использования / Вывод

$ ./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];
};

Это становится очень важным для удобства обслуживания при увеличении длины кода.

0 голосов
/ 08 ноября 2018

Для numMembers = sizeof (band [0]) / sizeof (band [0] .members);

sizeofband (band [0]) даст размер структуры одного канала - это 10 байтов для имени, а затем 20 * размер указателя.

SizeOf (полосы [0] .members); даст 20 * размер указателя

Не то, что вы хотите, так как sizeof не учитывает содержимое того, на что указывает указатель.

Также не учитывается, что некоторые из этих указателей на члены будут иметь значение NULL, поэтому вы не хотите их считать.

Возможно, лучше сделать:

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