cloopsinputscanftypedef

Typedef instances only saves the last input


I'm trying to get a few(3 for now) names as the candidates for a vote and assign them to typedef instances with the array I have defined. But when I run the code only the last name gets saved in the array as you can see in the second loop only the last input gets printed out. Can someone please let me know what I'm doing wrong here?

My code is:

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

}

Output:

Charlie
Ana 
David
Names: 
David
David
David

Solution

  • As noted astutely in comments, you are storing several copies of a pointer to the same string memory. You need each candidate to have its own memory to store a name. Given the size of the name, it makes sense to handle this without dynamic allocation.

    You also likely want to avoid magic numbers, and there's very little need for candidates to be scoped outside of the main function.

    Using fgets in place of scanf allows us to specify a maximum of NAME_SZ characters be read in, preventing a buffer overflow and allowing us to avoid hard-coded sizes in a scanf specifier's width field. To further tune this, you'd want to trim off any possible newline included. Using fgets also means that names do not have to be mononyms, but can include spaces.

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

    If you wish to use dynamic memory allocation, you can, but remember to free up the memory you allocated.

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