0

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);
    }
Dan
  • 129
  • 5
  • 3
    errr that's NOT how this works, you cannot pass the name of a field in a string and try to use that at runtime. C does not work like that. – Ahmed Masud Jul 16 '14 at 01:58
  • Seems you need to learn C. See the tag-wiki: https://stackoverflow.com/tags/c/info And this list of book recommendations: https://stackoverflow.com/questions/562303/the-definitive-c-book-guide-and-list – Deduplicator Jul 16 '14 at 02:03
  • use `offsetof` like [this](http://stackoverflow.com/a/23843770/971127). or write macro function. – BLUEPIXY Jul 16 '14 at 02:04
  • @Ahmed, What in your opinion could make my naming convention better? http://ideone.com/Y7L8Hu Here's the whole thing – Dan Jul 16 '14 at 02:05
  • @BLUEPIXY, I was considering taking advantage of some macro but I couldn't figure out what should it be like in this case. – Dan Jul 16 '14 at 02:08

3 Answers3

2

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.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • I like your way, I wonder why I didn't think of it myself! Yeah, I know that about gets, and scanf, and strcpy, too. – Dan Jul 16 '14 at 02:14
0

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;
}
Ahmed Masud
  • 21,655
  • 3
  • 33
  • 58
0

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;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
  • Thanks! Is using `offset` not possible in my case? Also, I've just tried to shrink repeating declarations and calls in `main` `#define initialize(name, number, TotalLegs) \` `do {\` `char str[1];\ int radix = 10;\ for (int n=0; n!=number; n++){\ pet* name_"n" = (pet*)malloc(sizeof(pet));\ addpet(name_"n", &TotalLegs);\/*this worked with name_number, but, quite obviously, it only creates 1 structure*/ }\ }while(0)` – Dan Jul 16 '14 at 11:32
  • @Dan _Is using offset not possible in my case?_ Although I think that it can use, of course, I thought this place's easy to match the format of the call original form(`writedata(Pet, string, name);`). – BLUEPIXY Jul 16 '14 at 11:36
  • Well, in that case, I'm all the more curious about the mistake I made trying to implement it. As for the code with broken formatting in my previous post: http://pastebin.com/Rkp7bYj5 My idea was to name it automatically in loop (Pet_0, Pet_1, Pet_3 ... Pet_n). – Dan Jul 16 '14 at 11:41
  • @Dan It is possible to create the name of the individual in the macro, but would be better served by using an array simply good. – BLUEPIXY Jul 16 '14 at 11:43
  • I only succeded at creating one name. My guess is that I would have to use something like _COUNTER_ macro, am I right? As for `offsetof` implementation, I followed http://stackoverflow.com/a/2044052/3829644 guide but to no avail. – Dan Jul 16 '14 at 11:53
  • name_n : E.g http://www.boost.org/doc/libs/1_55_0/libs/preprocessor/doc/ref/repeat_from_to.html – BLUEPIXY Jul 16 '14 at 12:09
  • Many thanks! _but would be better served by using an array simply good_ Could you please advise me some reading on this? I've only found a similar question on C# https://stackoverflow.com/questions/21008514/create-variable-names-using-items-from-a-string-array-in-c-sharp, but there are no dictionaries in C afaik. – Dan Jul 16 '14 at 12:36
  • @Dan `pet *Pet = malloc(n * sizeof(pet);` or `pet Pet[n];` use Pet[0]...Pet[n-1] – BLUEPIXY Jul 16 '14 at 13:13
  • Thanks! I got it. At first I thought you meant something like `pet_"string"`, but now that I've understood any idea other than just using simple arrays seems wrong and unnecessarily complicated to me. – Dan Jul 16 '14 at 14:19