Thread: Help! New to C

  1. #1
    C++ Newbie
    Join Date
    Nov 2005
    Posts
    49

    Exclamation Help! New to C

    I can't seem to get pointer conversions right, I've made a small Stash struct to hold things in bytes, but when I tried to output anything from the Stash it becomes NULL. Heres the code for the Stash.
    Code:
    typedef struct StashTag {
      size_t size;        /* Size of each space */
      int quantity;       /* Number of avaliable spaces */
      int items;          /* Number of items currently held */
      byte* storage;      /* Array of bytes */
    } Stash;
    
    /* Initialise and cleanup */
    void initialise(Stash* s, size_t data_size) {
      s->size = data_size;
      s->quantity = 0;
      s->items = 0;
      s->storage = NULL;
      return;
    }
    
    void clean(Stash* s) {
      if(s->storage != NULL) {
        free(s->storage);
      }
      s->size = 0;
      s->quantity = 0;
      s->items = 0;
      s->storage = NULL;
      return;
    }
    
    /* Memory routines */
    int inflate(Stash* s, int increase) {
      if(increase > 0) {
        int new_quantity = s->quantity+increase;
        int new_bytes = new_quantity*s->size;
        int old_bytes = s->quantity*s->size;
        int j;
        byte* new_storage = (byte*)malloc(new_quantity);
        if(s->storage != NULL) {
          for(j = 0; j < old_bytes; ++j) {
            new_storage[j] = s->storage[j];
          }
          free(s->storage);
        }
        s->storage = new_storage;
        s->quantity = new_quantity;
        return(1);
      }
      else {
        return(0);
      }
    }
    
    /* Stash operations */
    int put(Stash* s, const void* item) {
      if(sizeof((byte*)item) == s->size && s->items < s->quantity) {
        int start_location = s->items*s->size;
        int final_location = (s->items+1)*s->size;
        int j, k;
        byte* temp = (byte*)item;
        for(j = start_location, k = 0; j < final_location; ++j, ++k) {
          s->storage[j] = temp[k];
        }
        ++(s->items);
        return(s->items);
      }
      else {
        return(0);
      }
    }
    
    void* get(Stash* s, int item_number) {
      if(item_number > 0) {
        byte* segment = (byte*)malloc(s->size);
        int j, k;
        int start_location = (item_number-1)*s->size;
        int final_location = item_number*s->size;
        for(j = 0, k = start_location; k < final_location; ++j, ++k) {
          segment[j] = s->storage[k];
        }
        return((void*)segment);
      }
      else {
        return((void*)0);
      }
    }
    And this is the test-run.
    Code:
    int main() {
      Stash intStash;
      int i, j;
      
      initialise(&intStash, sizeof(int));
      inflate(&intStash, 100);
      for(i = 1; i < 15; ++i) {
        if(put(&intStash, &i)) {
          printf("done!");
        }
      }
      j = *((int*)get(&intStash, 15));
      printf("j is |%d|", j);
      
      printf("\n");
      system("PAUSE");
      return 0;
    }
    But it outputs "j is |0|", help!

  2. #2
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    You haven't populated element 15, so it is still zero.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  3. #3
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    I think that this line will not do what you expect.
    Code:
      if(sizeof((byte*)item) == s->size && s->items < s->quantity) {
    if I understand it right then you want to check if the new items size equals the datasize of the "stash".
    But the term "sizeof((byte*)item)" will allways return the size of a pointer ( 4 on ia32 ). Guess what you want to do is "sizeof(*item)". But that doesn't work because you cannot get the size of a void. In your test-run you are just lucky that sizeof(int) equals the size of a pointer.
    Kurt

  4. #4
    C++ Newbie
    Join Date
    Nov 2005
    Posts
    49
    Would this work then?
    Code:
    int put(Stash* s, const void* item) {
      byte* temp = (byte*)item;
      if(sizeof(*temp) == s->size && s->items < s->quantity) {
        int start_location = s->items*s->size;
        int final_location = (s->items+1)*s->size;
        int j, k;
        for(j = start_location, k = 0; j < final_location; ++j, ++k) {
          s->storage[j] = temp[k];
        }
        free(temp);
        ++(s->items);
        return(s->items);
      }
      else {
        free(temp);
        return(0);
      }
    }
    New test run still returns "j is 0"
    Code:
    int main() {
      Stash intStash;
      int i, j;
      
      initialise(&intStash, sizeof(int));
      inflate(&intStash, 100);
      i = 4;
      put(&intStash, &i);
      i = 8;
      put(&intStash, &i);
      j = *((int*)get(&intStash, 1));
      printf("j is %d", j);
      
      printf("\n");
      system("PAUSE");
      return 0;
    }
    [edit]Found the problem, how do I get the size of the entire array? I figured the condition in put will always be false since sizeof will return 1.[/edit]
    Last edited by Frost Drake; 12-16-2005 at 07:25 PM.

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,665
    > if(sizeof(*temp) == s->size && s->items < s->quantity)
    There is no point testing the size (the test is wrong anyway). You've already committed yourself to storing say ints when you did initialise(&intStash, sizeof(int));
    So all you can do here is test to see if you have room.

    > int put(Stash* s, const void* item)
    Three of your functions should return void - you ignore all the results anyway.

    > byte* temp = (byte*)item;
    Why are you casting this? C quietly casts to and from void* without trouble.
    If it's to remove the 'const', then thing about what you're really saying here.

    > free(temp);
    Now you're in deep doodoo - look at the call to the function, was it something you allocated using malloc - NO it isn't.
    You're lucky it even runs at all.

    > j = *((int*)get(&intStash, 1));
    The get function calls malloc, you need to call free here, but you lose the temporary pointer. This is a memory leak.
    int *temp = get(&intStash, 1); j = *temp ; free(temp);

  6. #6
    C++ Newbie
    Join Date
    Nov 2005
    Posts
    49
    Oh, yes. Thanks for the advice. I needed some functions to return an int because I thought that I might need it in if statements to test whether memory was allocated and other tasks that might need verification.

    About the casting, my compiler issues a warning:
    Code:
    43 C:\Dev-Cpp\User\LearnC\stash.c [Warning] initialization discards qualifiers from pointer target type
    Here's my new bits.
    Code:
    #define PASS 1
    #define FAIL 0
    
    typedef unsigned char byte;
    
    typedef struct StashTag {
      int size;           /* Size of each block space */
      int quantity;       /* Number of avaliable spaces */
      int items;          /* Number of items currently held */
      byte* storage;      /* Array of bytes */
    } Stash;
    
    void init(Stash* s, int block_size) {
      s->size = block_size;
      s->quantity = 0;
      s->items = 0;
      s->storage = NULL;
    }
    
    void kill(Stash* s) {
      if(s->storage != NULL) {
        free(s->storage);
      }
    }
    
    int inflate(Stash* s, int increase) {
      byte* temp;
      if((temp = (byte*)malloc(s->quantity+increase)) != NULL) {
        int old_bytes = s->quantity*s->size;
        int j;
        for(j = 0; j < old_bytes; ++j) {
          temp[j] = s->storage[j];
        }
        free(s->storage);
        s->storage = temp;
        s->quantity += increase;
        return PASS;
      }
      else {
        return FAIL;
      }
    }
    
    int store(Stash* s, const void* item) {
      if(s->items == s->quantity) {
        if(inflate(s, 1) != PASS) {
          return FAIL;
        }
      }
      int start_loc = s->items*s->size;
      int final_loc = (s->items+1)*s->size;
      int j, k;
      byte* _item = (byte*)item;
      for(j = start_loc, k = 0; j < final_loc; ++j, ++k) {
        s->storage[j] = _item[k];
      }
      ++s->items;
      return PASS;
    }

Popular pages Recent additions subscribe to a feed