Dan
Dan

Reputation: 129

Using a string as a variable part of structures's name in a function in plain C

I've encountered a problem trying to reduce the size of my code. What I was trying to do was passing either name or color to function writedata so that I wouldn't have to write it twice for each case.

typedef struct Pet{
    char* name;
    char* color;
} pet;
void writedata(pet *Pet, char string[], const char field[]){
    gets(string);
    Pet->field= (char*)malloc(strlen(string)+1);//I wanted it to be treated like Pet->name
    strcpy(Pet->field, string);
}

The call of the function:

 writedata(Pet, string, name);

I'm quite sure I got something wrong.

update: the whole code http://ideone.com/Y7L8Hu

update2: I tried to implement it using offset according to BLUEPIXY's advice but it seems I misunderstand manipulations with fields using their addresses... I believe the problem could be that the fields aren't initialized in the first place, but then again, my aim is to initialize them.

typedef struct Pet{
        char* name;
        int legs;
        char* color;
    } pet;
    void writedata(pet *Pet, size_t FIELD){
        char string[50];
        gets(string);
        (char*)Pet+offsetof(struct Pet, FIELD) = (char*)malloc(strlen(string)+1);//I wanted it to be treated like Pet->name
        strcpy((char*)Pet+FIELD, string);
    }

Upvotes: 0

Views: 148

Answers (3)

BLUEPIXY
BLUEPIXY

Reputation: 40145

use macro function sample.

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

#define writedata(var, buffer, field) \
    do {\
        int len = strlen(buffer);\
        var->field = (char*)malloc(len + 1);\
        memcpy(var->field, buffer, len+1);\
    }while(0)

typedef struct Pet{
    char* name;
    int legs;
    char* color;
    char* voice;
} pet;

void addpet(pet* Pet, int *TotalLegs){//Can not be used reference(&) in C
    char buff[50];
    int len;

    puts("Input name");
    scanf("%49[^\n]", buff);
    writedata(Pet, buff, name);

    puts("How many legs?");
    scanf("%d%*c", &Pet->legs);

    puts("What does it say?");
    scanf("%49[^\n]%*c", buff);
    writedata(Pet, buff, voice);

    puts("_____\n");
    *TotalLegs += Pet->legs;
}

int main(){
    int TotalLegs = 0;
    pet* Pet1  = (pet*)malloc(sizeof(pet));
    addpet(Pet1, &TotalLegs);
    pet* Pet2 = (pet*)malloc(sizeof(pet));
    addpet(Pet2, &TotalLegs);
    pet* Pet3 = (pet*)malloc(sizeof(pet));
    addpet(Pet3, &TotalLegs);
    //printf("%s\n", Pet1->name);
    //printf("%s\n", Pet1->voice);
    printf("The animals have %d legs\n", TotalLegs);
    free(Pet1);free(Pet2);free(Pet3);
    return 0;
}

Upvotes: 0

Ahmed Masud
Ahmed Masud

Reputation: 22372

A lot of things are wonky in your code.

What you wish to do can be achieved but it takes different type of code than you'd want to write.

What you really want to do is simply create a function that fills in a name and a color.

So here is the simplest way to do it:

typedef struct pet {
    char *name;
    char *color;
} pet_t;

pet_t * new_pet(const char *name, const char *color)
{
      pet_t *p;
      p = malloc(sizeof(pet_t));
      if ( p == NULL )
             return NULL;

      p->name = strdup(name); /* allocate space and copy string */
      p->color = strdup(color); /* allocate spance and copy string */

      return p;
}

void delete_pet(pet_t *p)
{
     if ( p-> name )
         free(p);

     if ( p->color) 
         free(color);

     if ( p ) 
         free(p);
}

int main() {
     pet_t *p;
     p = new_pet("Harry", "brown");
     printf("%s is a %s pet\n", p->name, p->color);
     delete_pet(p);
     return 0;
}

Upvotes: 0

Yu Hao
Yu Hao

Reputation: 122383

That's not how C works. However, I think using string comparison can achieve what you need:

if (strcmp(field, "name") == 0)
{
    Pet->name = ...
}
else if (strcmp(field, "color") == 0)
{
    Pet->color = ...
}

And call it with a string literal:

writedata(Pet, string, "name");

Using enum is also an option.


BTW, don't use gets, it's dangerous, use fgets instead.

Upvotes: 2

Related Questions