0

my current code:

#include <stdio.h>
#include <string.h>
/*
    struct Value {
       int typ;
       unsigned char vstring;
       int   vint;
       float  vfloat;
    };
*/
struct Value {
   int typ;
   /*
   type=1  ==> get vstring
   type=2  ==> get int
   type=3  ==> get float
   */
   union{
      struct{
         unsigned char *vstring;
      };
      struct{
         int   vint;
      };
      struct{
         float  vfloat;
      };
   }
};

void clear(Value vall){
   if(vall.typ == 1){
      delete(vall.vstring);
   }else if(vall.typ == 2){
      delete(vall.vint);
   }else{
      delete(vall.vfloat);
   }
}
int main()
{
   struct Value v;
   /////////////////////////////////////////////
   v.typ=1;
   strcpy( v.vstring,"C Programming/may this a very big utf-8 string!");
   /*
   strcpy( v.vint,4); 
   strcpy( v.vfloat,4.5);
   */
   /////////////////////////////////////////////
   printf( "ValueType : %d\n", v.typ);
   printf( "ValueString : %s\n", v.vstring);
   printf( "ValueInt : %d\n", v.vint);
   printf( "ValueFloat : %f\n", v.vfloat);
   return 0;
   Value copy=v;
   clear(copy);
   copy.typ=2;
   copy.vint=5;
}

but this have bug , and i not know how can fix this.

this have a Value struct. in this have (vstring,vint,vfloat) , and type of value store in typ for fast speed.

please help me to fix this code.

i will want store this struct in array/map/hashmap.... tank you.

GoWorkCode
  • 11
  • 8
  • 1
    `unsigned char vstring` should be `unsigned char *vstring` and you need to assign memory first to copy string. – Vagish Apr 19 '17 at 11:12
  • If it can be only one type at a time, you could use a [`union`](http://en.cppreference.com/w/c/language/union). – 001 Apr 19 '17 at 11:13
  • changed, but also again have errors. – GoWorkCode Apr 19 '17 at 11:24
  • what is `delete()`??? And how do you "delete" an int or a float? – Paul Ogilvie Apr 19 '17 at 11:31
  • delete() mean clear and delete from memory , i think can use `memset(, 0, MEMORY_BLOCK);` yes? or `#define CLEAR(x) memset(x,'\0',1000); CLEAR();`? – GoWorkCode Apr 19 '17 at 11:34
  • this line: `void clear(Value vall){` will not compile with a message about an 'incomplete type'. The line should be: `void clear( struct Value vall ){` – user3629249 Apr 19 '17 at 14:59
  • this line: `strcpy( v.vstring,"C Programming/may this a very big utf-8 string!");` is undefined behavior and can lead to a seg fault event because the pointer `v.vstring` has not been set to point to any specific memory so will copy the string to what every place in memory is indicated by the uninitialized trash is on the stack where the struct is located. – user3629249 Apr 19 '17 at 15:02
  • please check my code : http://ideone.com/dF7c6T , line 39 have problem. – GoWorkCode Apr 19 '17 at 15:06
  • Suggest insert a code block similar to `v.vstring = malloc( 100 ); if( !v.vstring ) { perror( "malloc failed"); exit( EXIT_FAILURE ); }` before the call to `strcpy()` However, since the string is a literal, might just use a pointer, similar to: `v.vstring = "C Programming/may this a very big utf-8 string!";` rather than a call to `strcpy()` – user3629249 Apr 19 '17 at 15:09
  • you say strcpy in old code, may check new source file ? http://ideone.com/dF7c6T – GoWorkCode Apr 19 '17 at 15:12

2 Answers2

0

A proper version of your code (but note the comments!) is:

struct Value {
   int typ;
   /*
   type=1  ==> get vstring
   type=2  ==> get int
   type=3  ==> get float
   */
   union{
     unsigned char *vstring;
     int   vint;
     float  vfloat;
   } u;
};

void clear(struct Value *vall){
   if(vall->typ == 1){
      {free(vall->u.vstring); vall->u.vstring= 0;}
   }else if(vall->typ == 2){
      vall->u.vint=0;
   }else{
      vall->u.vfloat=0.0;
   }
}
int main()
{
   struct Value v;
   /////////////////////////////////////////////
   v.typ=1;
   v.u.vstring= malloc(strlen("C Programming/may this a very big utf-8 string!")+1);
   strcpy( v.u.vstring,"C Programming/may this a very big utf-8 string!");
   /////////////////////////////////////////////
   printf( "ValueType : %d\n", v.typ);
   printf( "ValueString : %s\n", v.u.vstring);
   printf( "ValueInt : %d\n", v.u.vint);        // <== there is no int in u
   printf( "ValueFloat : %f\n", v.u.vfloat);    // <== there is no float in u
   return 0;
   struct Value copy=v; // <== you cannot do this as you now use the memory of the vstring
   clear(&copy);    // <== this now releases the memory of vstring in both 'copy' and 'v'
   copy.typ=2;
   copy.u.vint=5;
}
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
0

First, you might consider using a union. It's not required, but will save a few bytes:

struct Value {
   int typ;
   /*
   type=1  ==> get vstring
   type=2  ==> get int
   type=3  ==> get float
   */
   union {
    unsigned char *vstring;  // Changed to char pointer!!
    int   vint;
    float  vfloat;
   };
};

Next, when you copy the string, you need to allocate space:

const char *msg = "C Programming/may this a very big utf-8 string!";
struct Value v;
v.typ = 1;
v.vstring = malloc(strlen(msg) + 1);
strcpy(v.vstring, msg);
// strdup() does the same thing

And when you clear, you need to free that memory:

void clear(struct Value* vall){
   if (vall->typ == 1) {
      free(vall->vstring);
   }
   memset(vall, 0, sizeof(*vall));
}

Last, you can use an enum for the type, instead of "magic numbers":

enum VTYPE {VSTRING, VINT, VFLOAT};
typedef enum VTYPE vtype;

Also, here's a helper function to print:

void print_value(struct Value *v)
{
    static const char *types[] = {"VSTRING", "VINT", "VFLOAT"};
    printf( "ValueType : %s\n", v->typ >= 0 && v->typ < 3 ? types[v->typ] : "ERROR");
    if (VSTRING == v->typ) {
        printf( "ValueString : %s\n", v->vstring);
    }
    else if (VINT == v->typ) {
        printf( "ValueInt : %d\n", v->vint);
    }
    else if (VFLOAT == v->typ) {
        printf( "ValueFloat : %f\n", v->vfloat);
    }
}

Here's a link to the whole thing put together: http://ideone.com/ecy3qa

When you copy, be sure to duplicate the string:

void copy_value(struct Value *source, struct Value *dest) {
    if (VSTRING == source->typ) {
        dest->vstring = malloc(strlen(source->vstring) + 1);
        strcpy(dest->vstring, source->vstring);
    }
    else if (VINT == source->typ) {
        dest->vint = source->vint;
    }
    else if (VFLOAT == source->typ) {
        dest->vfloat = source->vfloat;
    }
    dest->typ = source->typ;
}
001
  • 13,291
  • 5
  • 35
  • 66
  • Perfect, Tank you. :like: – GoWorkCode Apr 19 '17 at 11:53
  • tank you @johnny-mopp , also may add a copy of `v`? http://paste.ubuntu.com/24413409/ , after clear `v`, also copy deleted! this bad. – GoWorkCode Apr 19 '17 at 12:00
  • You have to be careful when copying. If the type is `VSTRING` you need to make a duplicate of the string. Updated answer with copy function. – 001 Apr 19 '17 at 12:09
  • i make `struct Value coppy()` in http://paste.ubuntu.com/24413473/ , please check this. – GoWorkCode Apr 19 '17 at 12:15
  • You are not duplicating the string here: `v_r.vstring=v->vstring;` With that you will have 2 different objects pointing to the same string. So when you `clear(&v)`, `copy` will have an invalid pointer. – 001 Apr 19 '17 at 12:19
  • Done, tank you. :like: – GoWorkCode Apr 19 '17 at 12:24
  • Please if you have free time, answer another my question : http://stackoverflow.com/questions/43483396/how-substring-limit-using-c , tank you. good bye. – GoWorkCode Apr 19 '17 at 12:24
  • @GoWorkCode that q is closed so no answers can be added. But the posted answer notes, UTF-8 chars can be more than one byte. Maybe using [`wchar_t` strings](https://en.wikipedia.org/wiki/Wide_character) will help you. – 001 Apr 19 '17 at 14:03
  • tank you, i need `strlen()==>wcslen()` , `strcpy()==>??` for `w_char`. what name of funcs? – GoWorkCode Apr 19 '17 at 14:22
  • @GoWorkCode http://www.java2s.com/Tutorial/C/0300__Wide-Character-String/WideCharacterFunctions.htm – 001 Apr 19 '17 at 14:24
  • ```wchar_t *msg_n = L"C Programming/may this a very big utf-8 string!DONE!سلام"; wprintf(L"%ls",msg_n); ``` how fix this code? – GoWorkCode Apr 19 '17 at 14:47
  • First, you have ideone setup for Java. Change the language to C. Next, because `wchar_t` is bigger, change `malloc`s to: `malloc((wcslen(msg) + 1) * sizeof(wchar_t));` And when you use `wprintf` put an `L` in front of format string: `wprintf(L"ValueString : %s(%d)\n", v->vstring, v->size);` – 001 Apr 19 '17 at 15:13
  • `printf("%ls\n",v->vstring);` this is work in my source. but `wprintf` not work. – GoWorkCode Apr 19 '17 at 15:20
  • Yes, it's confusing. Try it on your pc. Also, reading this might help: http://stackoverflow.com/questions/26816547/whats-the-difference-between-printfs-printfls-wprintfs-and-wp – 001 Apr 19 '17 at 15:24