6

I'm trying to create an array of structs and also a pointer to that array. I don't know how large the array is going to be, so it should be dynamic. My struct would look something like this:

typedef struct _stats_t
{
 int hours[24]; int numPostsInHour;
 int days[7]; int numPostsInDay;
 int weeks[20]; int numPostsInWeek;
 int totNumLinesInPosts;
 int numPostsAnalyzed;

} stats_t;

... and I need to have multiple of these structs for each file (unknown amount) that I will analyze. I'm not sure how to do this. I don't like the following approach because of the limit of the size of the array:

# define MAX 10
typedef struct _stats_t
{
 int hours[24]; int numPostsInHour;
 int days[7]; int numPostsInDay;
 int weeks[20]; int numPostsInWeek;
 int totNumLinesInPosts;
 int numPostsAnalyzed;

} stats_t[MAX];

So how would I create this array? Also, would a pointer to this array would look something this?

stats_t stats[];
stats_t *statsPtr = &stats[0];
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Hristo
  • 45,559
  • 65
  • 163
  • 230
  • 1
    Questions: Can you manage a dynamic array of `int`? Can you manage a static array of `struct`? If there answer to either of these questions is "No.", I'd suggest working on that first. Once you can manage both of those, the answer to *this* should be obvious. Finally, you can find help on both of the above on Stack Overflow already. – dmckee --- ex-moderator kitten Apr 04 '10 at 21:19
  • 1
    The `_t` suffix is reserved for system headers. Don't use it. – Nicholas Shanks Apr 20 '18 at 09:24

5 Answers5

6

This is how it is usually done:

size_t n = <number of elements needed>
stats_t *ptr = malloc (n * sizeof (stats_t));

Then, to fill it in,

for (size_t j = 0;  j < n;  ++j)
{
   ptr [j] .hours = whatever
   ptr [j] .days = whatever
   ...
}
Nicholas Shanks
  • 10,623
  • 4
  • 56
  • 80
wallyk
  • 56,922
  • 16
  • 83
  • 148
  • 1
    a) You should use `size_t` instead of `int`. `int` is a signed type, and we rarely want to allocate an array with -1 length. b) I would use `sizeof *ptr` instead of `sizeof(stats_t)`, but it doesn't matter here. – Chris Lutz Apr 04 '10 at 21:30
  • Thank you for your responses. I understand how to allocate the memory and access it, but the problem is that I will malloc one struct at a time. Everytime a new file comes along, I will malloc another struct for it. So I can't malloc 'n' structs and then go back and do work on it, rather I need to say "Here's the array, expand (add to it) once every time a new file comes along." Does that make sense? – Hristo Apr 04 '10 at 21:34
  • @Hristo: For that, use the `realloc()` function to resize an array allocated with `malloc()`. That's why it's called dynamic allocation. – Chris Lutz Apr 04 '10 at 21:37
  • ahh... thanks. That is what I was looking for. Now I just need to learn how it works and the syntax. – Hristo Apr 04 '10 at 21:38
  • Using realloc each time the array grows is very inefficient. Better is double the array size each time. You'll need to keep track of how many are allocated separately from how many are used though. Another solution is to use a TAILQ or similar. Edit: sorry this is really old, didn't see that. – Per Johansson Dec 15 '12 at 18:23
2

The second option of a pointer is good.

If you want to allocate things dynamically, then try:

stats_t* theStatsPointer = (stats_t*) malloc( MAX * sizeof(stats_t) );

as Roland suggests.

Just don't forget to

free(theStatsPointer);

when you're done.

Peter K.
  • 8,028
  • 4
  • 48
  • 73
  • 1
    the problem is i don't know MAX right away... I don't know how many files I'll have to deal with so setting a MAX would be a bad idea. – Hristo Apr 04 '10 at 21:23
  • I don't want to repeat myself, but since your code is almost identical to sblom's (other than the correct declaration of `theStatsPointer`), see point b) in my comment there. But +1 for reminding us to `free()`. – Chris Lutz Apr 04 '10 at 21:35
  • @Chris: I didn't see sblorn's until after I posted. At the time I posted, I only saw Roland's post. – Peter K. Apr 04 '10 at 23:12
  • @Hristo: MAX does not have to be a constant. If you really must, you can always use realloc() if you exceed the already existing block of memory (of size MAX stats_t structs). D'oh! Just saw Chris Lutz's comment mentioning it too.... sorry for the dupe, Chris! ;-) – Peter K. Apr 04 '10 at 23:14
0

Use malloc():

http://en.wikipedia.org/wiki/Malloc

Roland Soós
  • 3,125
  • 4
  • 36
  • 49
0

malloc is your friend here.

stats_t stats[] = (stats_t*)malloc(N * sizeof(stats_t));

stats sort of is a pointer to the array. Or you can use stats[3] syntax as if it were declared explicitly as an array.

sblom
  • 26,911
  • 4
  • 71
  • 95
  • the problem is i don't know 'n' right away... I don't know how many files I'll have to deal with. – Hristo Apr 04 '10 at 21:23
  • a) You can't declare something like `stats_t stats[]`. That's an array with no size, not a pointer. You need `stats_t *stats`. b) I highly recommend against casting the return value of `malloc()` in C code, and the use of `sizeof(stats_t)`, both of which make changing the type of `stats` more complicated. The cast also has other, less justified stigmas associated with it. – Chris Lutz Apr 04 '10 at 21:29
  • What would you recommend instead of `sizeof`? – sblom Apr 04 '10 at 21:45
  • `sizeof`. :P I prefer the use of `sizeof *ptr` over `sizeof(type)` because if the type of `ptr` changes, `sizeof *ptr` adjusts automatically to the correct size, while `sizeof(type)` must be manually changed and is therefore more error prone. In this case, it doesn't matter because I doubt the type of `stats` will change, but in other cases it can be helpful. – Chris Lutz Apr 04 '10 at 23:30
  • @ChrisLutz Ironically, I just used your suggestion for the first time in my C code, and then within 60 seconds had to rename the variable, and so had to change the `sizeof` parameter too! – Nicholas Shanks Apr 20 '18 at 09:31
0

Based on your replies to other answers it looks like you need a dynamic data structure like a linked list. Take a look at the queue(3) set of facilities.

Nikolai Fetissov
  • 82,306
  • 11
  • 110
  • 171