#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    27
    Rep Power
    0

    Unknown data type to be stored?


    I'm writing a code using a structure wich will store certain data, but the data type will be defined later.

    What I've done until now was creating variables:
    Code:
    struct structname{
    char datatype
    int integer;
    char character;
    char[20] string;
    float floating;
    ...
    more pointers
    }
    So I scan the type using the a certain letter and then I store the data on the compatible variable.

    And now I have a function like this:

    Code:
    structurename* functionname(char * type, void * data){
        structurename *p;
        p = malloc(sizeof(structurename));
    
    
        p->datatype = *type;
    
        if     (type = "d") p->integer = (int)data;
        else if(type = "f") p->floating = (float)data;
        else if(type = "c") p->character = (char)data;
        //else if(type = "s") p->string = (char[])data ;
    
       return p;
    }
    Just some notes: I'll need the datatype stored in the structure for later use.

    On the bold part: it works for the first case, but the other cases give me errors:
    pointer value used where floating point value was expected.
    cast from pointer to integer of different size [-Wpointer-to-int-cast]

    I'm almost sure I'm messing up on converting the void to a string in the last case.

    Anyway, are there better options to store different types of data in a structure when I don't know wich type they are?
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    C or C++? Your code is ambiguous as to which it is that you are using (what with mixing string and malloc).
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    27
    Rep Power
    0
    Originally Posted by dwise1_aol
    C or C++? Your code is ambiguous as to which it is that you are using (what with mixing string and malloc).
    It's C, where I wrote string I meant char[20], I'll just edit it.
  6. #4
  7. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,843
    Rep Power
    480
    Unions consume less space than structs for this application.
    Code:
    int main() {
      struct {
        char type;
        union {
          int i;
          float f;
        };
      } datum;
      datum.type = 'i';
      datum.i = 0;
      return datum.i;
    }
    [code]Code tags[/code] are essential for python code and Makefiles!
  8. #5
  9. Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2009
    Posts
    149
    Rep Power
    36
    Are these actually in a struct? If so can we see your struct definition? It is hard to guess at what your errors mean without all of the relevant code.
  10. #6
  11. Banned ;)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2001
    Location
    Woodland Hills, Los Angeles County, California, USA
    Posts
    9,616
    Rep Power
    4247
    This code won't work:
    Originally Posted by VicFS
    Code:
    
        if     (type = "d") p->integer = (int)data;
        else if(type = "f") p->floating = (float)data;
        else if(type = "c") p->character = (char)data;
        //else if(type = "s") p->string = (char[])data ;
    Why? Because type is a char *. First, C's equality operator is ==, not = (which is the assignment operator). Second, when comparing two strings in C, you have to use strcmp(). And to copy strings, you have to use strcpy or a safer function such as snprintf() E.g.
    Code:
        if     (strcmp(type, "d") == 0) ...
        else if (strcmp(type, "f") == 0) ...
        else if (strcmp(type, "s") == 0) {
            snprintf(p->string, sizeof(structurename.string), "%s", (char *) data);
    Second, how are you calling your functionname() when passing it a float argument? Are you typecasting the second argument from a float to a void*, or are you passing the address of the float variable. The same holds for int variables as well as char. What I'd like to know is which way are you calling functionname:
    Code:
    int abc = 123;
    float xyz = 123.45;
    
    functionname("i", (void *)abc);
    functionname("f", (void *)xyz);
    or
    functionname("i", (void *)&abc);
    functionname("f", (void *)&xyz);
    The differences are subtle but important, especially if you're dealing with a 32-bit OS, because a 32-bit pointer is not wide enough to hold a float (which is typically 48-bit). You should really be using the second form regardless of OS/compiler and in your functionname, you should code as:
    Code:
        if     (strcmp(type, "d") == 0) {
            p->integer = *((int *)data);
        }
        else if (strcmp(type, "f") == 0) {
            p->floating = *((float *)data);   
        }
        ....
    There is a bit of vaxocentrism assumed here, but it should generally work :).


    Thirdly, it might be a good idea to use unions inside a struct like b49P23TIvg suggested:
    Code:
    typedef struct {
        char datatype;
        union { 
            int integer;
            float floating;
            char character;
            char[20] string;
        }
    } structurename;
    
    structurename* functionname(char type, void * data) {
        structurename *p;
        p = malloc(sizeof(structurename));
    
        p->datatype = type;
        if (type == 'd') {
            p->integer = *((int *)data);
        }
        else if (type == 'f') {
            p->floating = *((float *)data);   
        }
        ...
        ...
        return p;
    }
    Up the Irons
    What Would Jimi Do? Smash amps. Burn guitar. Take the groupies home.
    "Death Before Dishonour, my Friends!!" - Bruce D ickinson, Iron Maiden Aug 20, 2005 @ OzzFest
    Down with Sharon Osbourne

    "I wouldn't hire a butcher to fix my car. I also wouldn't hire a marketing firm to build my website." - Nilpo
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    27
    Rep Power
    0
    Originally Posted by Scorpions4ever
    Why? Because type is a char *. First, C's equality operator is ==, not = (which is the assignment operator).
    Second, when comparing two strings in C, you have to use strcmp(). And to copy strings, you have to use strcpy or a safer function such as snprintf() E.g.
    Code:
        if     (strcmp(type, "d") == 0) ...
        else if (strcmp(type, "f") == 0) ...
        else if (strcmp(type, "s") == 0) {
            snprintf(p->string, sizeof(structurename.string), "%s", (char *) data);
    I thought I could compare single characters, like sometimes when you need to find the end of a string you can use ( char[i] != '\0'), in fact, I tryed to use "==" and I was getting an error, but after switching to an "=" the first comparision line was fine according to the compiler.

    Originally Posted by Scorpions4ever
    Second, how are you calling your functionname() when passing it a float argument? Are you typecasting the second argument from a float to a void*, or are you passing the address of the float variable. The same holds for int variables as well as char. What I'd like to know is which way are you calling functionname:
    Code:
    int abc = 123;
    float xyz = 123.45;
    
    functionname("i", (void *)abc);
    functionname("f", (void *)xyz);
    or
    functionname("i", (void *)&abc);
    functionname("f", (void *)&xyz);
    The differences are subtle but important, especially if you're dealing with a 32-bit OS, because a 32-bit pointer is not wide enough to hold a float (which is typically 48-bit). You should really be using the second form regardless of OS/compiler and in your functionname, you should code as:
    Code:
        if     (strcmp(type, "d") == 0) {
            p->integer = *((int *)data);
        }
        else if (strcmp(type, "f") == 0) {
            p->floating = *((float *)data);   
        }
        ....
    There is a bit of vaxocentrism assumed here, but it should generally work :).
    I was using the first form, I'll use the second now and rewrite some parts of the code

    Originally Posted by Scorpions4ever
    Thirdly, it might be a good idea to use unions inside a struct like b49P23TIvg suggested:
    Code:
    typedef struct {
        char datatype;
        union { 
            int integer;
            float floating;
            char character;
            char[20] string;
        }
    } structurename;
    
    structurename* functionname(char type, void * data) {
        structurename *p;
        p = malloc(sizeof(structurename));
    
        p->datatype = type;
        if (type == 'd') {
            p->integer = *((int *)data);
        }
        else if (type == 'f') {
            p->floating = *((float *)data);   
        }
        ...
        ...
        return p;
    }
    Thank you for the reply, made me see how to fix my erros and even figure out more efficient ways for other parts of the code.


    Originally Posted by jakotheshadows
    Are these actually in a struct? If so can we see your struct definition? It is hard to guess at what your errors mean without all of the relevant code.
    The struct definition was in the first code wrap, I'll edit it, so it becomes more clear. I'm sorry.
  14. #8
  15. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,843
    Rep Power
    480
    Originally Posted by VicFS
    I thought I could compare single characters, like sometimes when you need to find the end of a string you can use ( char != '\0'), in fact, I tryed to use "==" and I was getting an error, but after switching to an "=" the first comparision line was fine according to the compiler.
    You need to understand that switching `==' to `=' changes the expression from a comparison to an assignment.

    And I'd test with, for example,
    'f' == *type
    or, if you prefer,
    'f' == type[0]

    In ( Char != '\0') the types agree.
    [code]Code tags[/code] are essential for python code and Makefiles!
  16. #9
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    27
    Rep Power
    0
    I finished the code, but even when it works on my computer for every possible test I can think, when I send to the system that tests the code, it's getting an execution error in most of the tests.

    I think I might be acessing something wrong with the pointers wich works on my computer but doesn't on the system.

    Anyway I'll post some functions, is there anything that could be causing the execution error?

    EDIT: error was in this function, thanks b49P23TIvg for pointing it.
    Code:
    
    void deletelist(list * l){
        node *p;
        p = l->head;
        while(l->size >0){
            l->head = p->next;
            free(p);
            free(p->s);
            p = l->head;
            l->size--;
        }
        free(l);
    }
  18. #10
  19. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,843
    Rep Power
    480
    Your program fails
    Code:
    void deletelist(list * l){
      node *p;
      p = l->head;
      while(l->size >0){
        l->head = p->next;
        free(p);
        free(p->s); /*******************HERE********/
        p = l->head;
        l->size--;
      }
      free(l);
    }
    Code:
    struct node{ 
      char type;
      char s[200]; /******you didn't allocate array s you cannot free s****/
    ...
    By ignoring the return value from newnode you avoided caring for the potential out-of-memory problem.
    Last edited by b49P23TIvg; March 10th, 2013 at 09:17 PM.
    [code]Code tags[/code] are essential for python code and Makefiles!
  20. #11
  21. Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2009
    Posts
    149
    Rep Power
    36
    First off, this whole if / else if / else if business will look a lot cleaner with a switch case since you have four cases and they're all on the value of p->type.

    Code:
     else if(p->type == 's') snprintf (p->s, sizeof(((node*)0)->s), "%s", (char *) data);
    Secondly, what is this? "sizeof(((node*)0)->s)"

    If you're trying to tell snprintf not to write more than 200 chars worth of data, then do that. Maybe there is something here I am missing, but this looks like gibberish to me.

    Try sizeof(char)*200 if you're trying to limit it to writing no more than 200 chars. If you want to be more accurate, and you can guarantee that p->s is a valid c string, you can do sizeof(char)*(strlen(p->s)+1) to be more precise.

    Also, give b49's post a read. You don't need to free p->s since it is allocated in the same malloc where you create p in the first place. This means that when you free p, you're freeing up the entire struct that p points to. The only reason you'd need to free members of the struct individually is if you malloc individual members of that struct, and even then you would want to do this BEFORE freeing p, otherwise you would have no reference from which to free those members.
  22. #12
  23. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    27
    Rep Power
    0
    Originally Posted by jakotheshadows
    First off, this whole if / else if / else if business will look a lot cleaner with a switch case since you have four cases and they're all on the value of p->type.

    Code:
     else if(p->type == 's') snprintf (p->s, sizeof(((node*)0)->s), "%s", (char *) data);
    Secondly, what is this? "sizeof(((node*)0)->s)"

    If you're trying to tell snprintf not to write more than 200 chars worth of data, then do that. Maybe there is something here I am missing, but this looks like gibberish to me.

    Try sizeof(char)*200 if you're trying to limit it to writing no more than 200 chars. If you want to be more accurate, and you can guarantee that p->s is a valid c string, you can do sizeof(char)*(strlen(p->s)+1) to be more precise.

    Also, give b49's post a read. You don't need to free p->s since it is allocated in the same malloc where you create p in the first place. This means that when you free p, you're freeing up the entire struct that p points to. The only reason you'd need to free members of the struct individually is if you malloc individual members of that struct, and even then you would want to do this BEFORE freeing p, otherwise you would have no reference from which to free those members.
    As for freeing the string, I thought allocating the node would also allocate the space for the char array since the node includes a pointer to a that array. Thought freeing the node would only free it's structure, cleaning the pointer to the array, but not the memory allocated for it. Anyway, that solved the problem, thanks for helping me find the error.

    As for the snprintf, to be honest, I don't recall how or why I used that syntax, but I was having some trouble where it would store less characters than I needed, I might have read somewhere and used (in fact, it works this way). I know I'm wrong for using something I don't know exactly how it works, just because it works, but I'm still unexperienced at programming.
  24. #13
  25. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,843
    Rep Power
    480
    Originally Posted by VicFS
    I know I'm wrong for using something I don't know exactly how it works,
    I agree. People who don't have a detailed understanding of thermodynamics shouldn't drive. People who bash science shouldn't be allowed cell phones.
    [code]Code tags[/code] are essential for python code and Makefiles!
  26. #14
  27. Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2009
    Posts
    149
    Rep Power
    36
    I might have read somewhere and used (in fact, it works this way)
    I'm an inexperienced programmer too. It is just that I've never seen that before now so I have no idea what it means, and the ways I've seen and told you about seem much more readable.

    Though it seems that it doesn't dereference a null pointer like I was thinking, so I suppose it is safe.
    http://stackoverflow.com/questions/3553296/c-sizeof-single-struct-member

IMN logo majestic logo threadwatch logo seochat tools logo