Я пытаюсь получить несколько (на данный момент 3) имен в качестве кандидатов на голосование и назначить их экземплярам typedef с помощью определенного мной массива. Но когда я запускаю код, в массиве сохраняется только фамилия, как вы можете видеть во втором цикле, распечатывается только последний ввод. Может кто-нибудь, пожалуйста, дайте мне знать, что я делаю здесь неправильно?
Мой код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *name;
int votes;
}
candidate;
#define MAX 9
candidate candidates[MAX];
int main(void)
{
char candid[10];
for (int i =0; i<3; i++)
{
scanf("%s",candid);
candidates[i].name = candid;
candidates[i].votes = 0;
}
printf("Names: \n");
for (int i = 0; i < 3; i++)
{
printf("%s\n",candidates[i].name);
}
}
Выход:
Charlie
Ana
David
Names:
David
David
David
Как проницательно отмечено в комментариях, вы храните несколько копий указателя на одну и ту же строковую память. Вам нужно, чтобы у каждого candidate
была собственная память для хранения имени. Учитывая размер имени, имеет смысл обойтись без динамического выделения.
Вы также, вероятно, захотите избежать магических чисел, и нет необходимости в том, чтобы candidates
выходил за пределы функции main
.
Использование fgets
вместо scanf
позволяет нам указать максимум NAME_SZ
символов для чтения, предотвращая переполнение буфера и позволяя нам избежать жестко запрограммированных размеров в поле ширины спецификатора scanf
. Для дальнейшей настройки вам нужно обрезать любую возможную новую строку. Использование fgets
также означает, что имена не обязательно должны быть мононимами, но могут включать пробелы.
#include <stdio.h>
#define NAME_SZ 20
#define MAX_CANDIDATES 3
typedef struct {
char name[NAME_SZ];
int votes;
} candidate;
int main(void) {
candidate candidates[MAX_CANDIDATES];
for (int i = 0; i < MAX_CANDIDATES; i++) {
fgets(candidates[i].name, NAME_SZ, stdin);
candidates[i].votes = 0;
}
printf("Names: \n");
for (int i = 0; i < MAX_CANDIDATES; i++) {
printf("%s\n", candidates[i].name);
}
}
Если вы хотите использовать динамическое распределение памяти, вы можете это сделать, но не забудьте освободить выделенную память.
#include <stdio.h>
#define NAME_SZ 20
#define MAX_CANDIDATES 3
typedef struct {
char *name;
int votes;
} candidate;
int main(void) {
candidate candidates[MAX_CANDIDATES];
for (int i = 0; i < MAX_CANDIDATES; i++) {
char name[NAME_SZ];
fgets(name, NAME_SZ, stdin);
candidates[i].name = malloc(strlen(name) + 1);
strcpy(candidates[i].name, name);
// Or just use strdup:
// candidates[i].name = strdup(name);
candidates[i].votes = 0;
}
printf("Names: \n");
for (int i = 0; i < MAX_CANDIDATES; i++) {
printf("%s\n", candidates[i].name);
// Assuming we don't need them further,
// we can clean up here.
free(candidates[i].name);
}
}
Также стоило бы добавить ссылку на Как предотвратить переполнение буфера scanf() в C?, хотя, поскольку я упомянул об этом здесь, теперь это менее критично. И я полностью согласен, что 10 было удручающе мало для имени кандидата.
Если это ответ на ваш вопрос, вы можете пометить его как принятый. Когда вы получите больше репутации, вы также сможете сказать спасибо, проголосовав за ответы.
Есть только одна строка
candid
. Все элементы вашего массива имеют указатель на этот же массив. Либо измените структуру на использованиеchar name[10];
, а затем используйтеstrcpy()
, либо используйтеcandidates[i].name = strdup(candid);