By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,305 Members | 1,614 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,305 IT Pros & Developers. It's quick & easy.

array of pointers to struct as function parameter

P: 2
I am coding in C. I have a dynamic array of pointers (*MyStrPtr) which passed to function GetBuffer. The length of the array can be known inside the GetBuffer only. So allocation of MyStrPtr must be done within GetBuffer also. Within GetBuffer, MyStrPtr is filled with data. I want GetBuffer to return the stored value of name of the first element of MyStrPtr.

I want retrieve within main all the data stored in MyStrPtr. I don't know how to do this. My code below does not work properly. Also I want to avoid memory leaks.

Any help will be very much appreciated. Thank you in advance.



Expand|Select|Wrap|Line Numbers
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. typedef struct {
  6.   char *name;
  7.   int   number;
  8. } MyStr;
  9.  
  10. typedef MyStr* MyStrPointer;
  11.  
  12. int GetNumberOfMyStrs(void);
  13. MyStr * GetNextMyStr(void);
  14. char * GetBuffer(MyStrPointer *MyStrPtr, int *size);
  15.  
  16. int main()
  17. {
  18.   char *str;
  19.   MyStrPointer *MyStrPtr;
  20.   int numseq;
  21.   int i;
  22.  
  23.   str=GetBuffer(MyStrPtr, &numseq);
  24.  
  25.   printf("String b: %s", str);
  26.  
  27.   /*I want to retrieve the contents of MyStrPtr also*/
  28.   /* NOT WORKING */
  29.   printf("\nPrint strings (in main).\n");
  30.   for (i=0; i<numseq; i++) {
  31.     printf("String %d : %s", i, MyStrPtr[i]->name);
  32.     printf("Size : %d\n", MyStrPtr[i]->number);
  33.   }
  34.  
  35.   /* I want to free MyStrPtr */
  36.   /* NOT WORKING */
  37.   printf("Free memory\n");
  38.       for (i=0; i<numseq; i++) {
  39.     printf("%d ", i);
  40.     free(MyStrPtr[i]->name);
  41.   }
  42.  
  43.   free(MyStrPtr);
  44.  
  45.   return 0;
  46. }
  47.  
  48. int GetNumberOfMyStrs(void) {
  49.   int value;
  50.  
  51.   /* Consider a simple case */
  52.   value = 3;
  53.   return value;
  54. }
  55.  
  56. MyStr * GetNextMyStr(void) {
  57.   char string[100];
  58.   int length;
  59.  
  60.   static MyStr seq;
  61.  
  62.   printf("Enter string\n");
  63.   fgets(string, sizeof(string), stdin);
  64.   length = strlen(string);
  65.  
  66.   seq.name=malloc(length*sizeof(char));
  67.   strcpy(seq.name, string);
  68.   seq.number = length;
  69.   return &seq;
  70. }
  71.  
  72. char * GetBuffer(MyStrPointer *MyStrPtr, int *size) {
  73.   MyStrPointer SSPtr;
  74.   int length;
  75.   int i;
  76.  
  77.   *size = GetNumberOfMyStrs();
  78.   MyStrPtr = malloc(*size * sizeof(MyStrPointer));
  79.  
  80.   for (i=0; i<*size; i++) {
  81.     SSPtr = GetNextMyStr();
  82.     MyStrPtr[i] = malloc(sizeof(MyStr));
  83.     MyStrPtr[i]->name = malloc((*SSPtr).number*sizeof(char));
  84.     strcpy(MyStrPtr[i]->name, (*SSPtr).name);
  85.     MyStrPtr[i]->number = (*SSPtr).number;
  86.   }
  87.  
  88.   free(SSPtr);
  89.   return (MyStrPtr[0]->name);
  90. }
Jun 25 '06 #1
Share this Question
Share on Google+
3 Replies


100+
P: 293
D_C
Is STL off limits? Because I was having trouble with dynamic sized arrays, then I just used <vector> from STL, and everything worked beautifully.

Edit: STL works for C++, I'm not sure it works for C. I should have paid more attention to that.
Jun 25 '06 #2

P: 2
STL is off-limits :mad:

It requires me to do it in pure C.
Jun 25 '06 #3

Banfa
Expert Mod 5K+
P: 8,916
OK sorry about the delay, this is quite a large question and I have been putting off the answer until I had the time to give it my full attention.

Firstly a little tutorial on returning values from functions via parameters (rather than just as the return value of a function).

If you want to return a value from a function via a parameter then the parameter needs to point to the type that you wish to return, this can be generalized as

Expand|Select|Wrap|Line Numbers
  1.     /* Give type T as the type required */
  2.  
  3.     extern fn( T *pRV);   /* Declare Function */
  4.  
  5.     T RV;                 /* Declare data */
  6.  
  7.     fn(&RV);              /* Call function */
  8.  
  9.     /* RV now contains your return data (assuming fn works) */
  10.  
This works for any data type so if you want to return an int then T is int and the function takes pointer to int. If you want to return a pointer to a structure MyStr then T is MyStr * and the function takes pointer to MyStr * or MyStr **.

Onto your code, I am going to embed specific comments in bold below however first a general comment.

Comparing you code with my mini tutorial you will see that you declare your function correctly, however you make a mistake in calling it (and it is a mistake I see often). Instead of having a variable of type T and passing &T to the function you have a variable of type T * and pass T to the function. Since you have not passed a pointer to any local data to the function it can not pass back any results that you can see. The error lies in your data declaration and function call mainly rather than the implementation of the function.

Expand|Select|Wrap|Line Numbers
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. typedef struct {
  6.   char *name;
  7.   int   number;
  8. } MyStr;
  9.  
  10. typedef MyStr* MyStrPointer;
  11.  
  12. int GetNumberOfMyStrs(void);
  13. MyStr * GetNextMyStr(void);
  14. char * GetBuffer(MyStrPointer *MyStrPtr, int *size);
  15.  
  16. int main()
  17. {
  18.   char *str;
  19.   MyStrPointer *MyStrPtr;
  20. /* This declaration is wrong, you want an array of MyStr, arrays and 
  21.    pointer (in some circumstances) can be treated similarly so to get a 
  22.    dynamicly allocated array you need a pointer to MyStr (MyStr * or 
  23.    MyStrPointer).  However you have declared a pointer to pointer to 
  24.    MyStr (MyStr ** or MyStrPointer *. Correct this to
  25.  
  26.   MyStrPointer MyStrPtr;
  27.  
  28. */
  29.  
  30.   int numseq;
  31.   int i;
  32.  
  33.   str=GetBuffer(MyStrPtr, &numseq);
  34. /* You have called this function pasing the first value BY Value rather 
  35.    than BY Reference.  This causes undefined behaviour because the 
  36.    function writes to *MyStrPtr but you have not initialised this variable 
  37.    so GetBuffer will be writing to some random memory location.  As 
  38.    soon as you invoke undefined behaviour all bets are off, the program 
  39.    is free to do whatever it wants.  With the correction above you correct this to
  40.  
  41.   str=GetBuffer(&MyStrPtr, &numseq);
  42. */
  43.  
  44.   printf("String b: %s", str);
  45.  
  46.   /*I want to retrieve the contents of MyStrPtr also*/
  47.   /* NOT WORKING */
  48.   printf("\nPrint strings (in main).\n");
  49.   for (i=0; i<numseq; i++) {
  50.     printf("String %d : %s", i, MyStrPtr[i]->name);
  51. /* MyStrPtr was never properly initialised so this access and all 
  52.    further accesses in main are undefined behaviour, that it is merely 
  53.    not working as opposed to crashing spectacularly is amazing in itself.
  54.  
  55.    Once the fixes suggested above are implemented then this will need 
  56.    to change to
  57.  
  58.     printf("String %d : %s", i, MyStrPtr[i].name);
  59.  
  60.    which looks like a proper array access.  That should have given you a 
  61.    clue, you were try to set up a dynamic array but did not end up with 
  62.    syntax that looked like an array access. */
  63.     printf("Size : %d\n", MyStrPtr[i]->number);
  64.   }
  65.  
  66.   /* I want to free MyStrPtr */
  67.   /* NOT WORKING */
  68.   printf("Free memory\n");
  69.       for (i=0; i<numseq; i++) {
  70.     printf("%d ", i);
  71.     free(MyStrPtr[i]->name);
  72.   }
  73.  
  74.   free(MyStrPtr);
  75.  
  76.   return 0;
  77. }
  78.  
  79. int GetNumberOfMyStrs(void) {
  80.   int value;
  81.  
  82.   /* Consider a simple case */
  83.   value = 3;
  84.   return value;
  85. }
  86.  
  87. MyStr * GetNextMyStr(void) {
  88.   char string[100];
  89.   int length;
  90.  
  91.   static MyStr seq;
  92.  
  93.   printf("Enter string\n");
  94.   fgets(string, sizeof(string), stdin);
  95.   length = strlen(string);
  96.  
  97.   seq.name=malloc(length*sizeof(char));
  98.   strcpy(seq.name, string);
  99. /* These 2 lines emboddy a buffer overrun error (also undefined behaviour)
  100.    You only allocate length bytes where length is strlen but then use strcpy 
  101.    to copy the data to the buffer.  Consider the string "Ben" it has a strlen of 
  102.    3 but uses 4 bytes of memory because it has a zero terminator.  Your code
  103.    does not take account of the zero terminator that strcpy will put at the end 
  104.    of the buffer.  You need to either allocate 1 extra byte of memory or use 
  105.    memcpy and only copy length bytes. */
  106.   seq.number = length;
  107.   return &seq;
  108. }
  109.  
  110. char * GetBuffer(MyStrPointer *MyStrPtr, int *size) {
  111.   MyStrPointer SSPtr;
  112.   int length;
  113.   int i;
  114.  
  115.   *size = GetNumberOfMyStrs();
  116.   MyStrPtr = malloc(*size * sizeof(MyStrPointer));
  117. [b]/* You are trying to pass back an array of MyStr so that ios what 
  118.    you should allocate, not an array of pointers to MyStr.  Also to 
  119.    pass data back you need to be dereferencing  pointer (the same 
  120.    as you have correctly done for the size variable.  Fixed this becomes
  121.  
  122.   *MyStrPtr = malloc(*size * sizeof(MyStr));
  123.  
  124.    this allocates data for the required number of structures in a single 
  125.    block, which is what an array of structure is.
  126. */[b]
  127.  
  128.   for (i=0; i<*size; i++) {
  129.     SSPtr = GetNextMyStr();
  130.     MyStrPtr[i] = malloc(sizeof(MyStr));
  131. /* This malloc is superfluous and just needs removing */
  132.     MyStrPtr[i]->name = malloc((*SSPtr).number*sizeof(char));
  133. /* Accessing the array of structures you need to dereference to get the 
  134.    array the index into the array, not the other way around now, 
  135.    this becomes
  136.  
  137.     (*MyStrPtr)[i].name = malloc((*SSPtr).number*sizeof(char));
  138.  
  139.    This applies to other lines below.
  140. */ 
  141.     strcpy(MyStrPtr[i]->name, (*SSPtr).name);
  142. /* Again you have only malloc'd strlen bytes but copied strlen + 1 bytes 
  143.    to the buffer returned. */
  144.     MyStrPtr[i]->number = (*SSPtr).number;
  145.   }
  146.  
  147.   free(SSPtr);
  148. /* SSPtr was never allocated, however SSPtr->name or (*SSPtr).name 
  149.    (and I perfer the first notation) is allocated every time you go round the 
  150.    loop above.  this should be
  151.  
  152.   free((*SSPtr).name);
  153.  
  154. and moved inside the loop 
  155.  
  156. Needless to say freeing non allocated memory is undefined behaviour
  157. */
  158.  
  159.   return (MyStrPtr[0]->name);
  160. }

OK I hope that helps, get back to us if you need further help.
Jun 26 '06 #4

Post your reply

Sign in to post your reply or Sign up for a free account.