You've tagged this as C++ as well as C.
If you're using C++ things are a lot easier. The standard template library has a template called vector which allows you to dynamically build up a list of objects.
#include <stdio.h>
#include <vector>
typedef std::vector<char*> words;
int main(int argc, char** argv) {
words myWords;
myWords.push_back("Hello");
myWords.push_back("World");
words::iterator iter;
for (iter = myWords.begin(); iter != myWords.end(); ++iter) {
printf("%s ", *iter);
}
return 0;
}
If you're using C things are a lot harder, yes malloc, realloc and free are the tools to help you. You might want to consider using a linked list data structure instead. These are generally easier to grow but don't facilitate random access as easily.
#include <stdio.h>
#include <stdlib.h>
typedef struct s_words {
char* str;
struct s_words* next;
} words;
words* create_words(char* word) {
words* newWords = malloc(sizeof(words));
if (NULL != newWords){
newWords->str = word;
newWords->next = NULL;
}
return newWords;
}
void delete_words(words* oldWords) {
if (NULL != oldWords->next) {
delete_words(oldWords->next);
}
free(oldWords);
}
words* add_word(words* wordList, char* word) {
words* newWords = create_words(word);
if (NULL != newWords) {
newWords->next = wordList;
}
return newWords;
}
int main(int argc, char** argv) {
words* myWords = create_words("Hello");
myWords = add_word(myWords, "World");
words* iter;
for (iter = myWords; NULL != iter; iter = iter->next) {
printf("%s ", iter->str);
}
delete_words(myWords);
return 0;
}
Yikes, sorry for the worlds longest answer. So WRT to the "don't want to use a linked list comment":
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char** words;
size_t nWords;
size_t size;
size_t block_size;
} word_list;
word_list* create_word_list(size_t block_size) {
word_list* pWordList = malloc(sizeof(word_list));
if (NULL != pWordList) {
pWordList->nWords = 0;
pWordList->size = block_size;
pWordList->block_size = block_size;
pWordList->words = malloc(sizeof(char*)*block_size);
if (NULL == pWordList->words) {
free(pWordList);
return NULL;
}
}
return pWordList;
}
void delete_word_list(word_list* pWordList) {
free(pWordList->words);
free(pWordList);
}
int add_word_to_word_list(word_list* pWordList, char* word) {
size_t nWords = pWordList->nWords;
if (nWords >= pWordList->size) {
size_t newSize = pWordList->size + pWordList->block_size;
void* newWords = realloc(pWordList->words, sizeof(char*)*newSize);
if (NULL == newWords) {
return 0;
} else {
pWordList->size = newSize;
pWordList->words = (char**)newWords;
}
}
pWordList->words[nWords] = word;
++pWordList->nWords;
return 1;
}
char** word_list_start(word_list* pWordList) {
return pWordList->words;
}
char** word_list_end(word_list* pWordList) {
return &pWordList->words[pWordList->nWords];
}
int main(int argc, char** argv) {
word_list* myWords = create_word_list(2);
add_word_to_word_list(myWords, "Hello");
add_word_to_word_list(myWords, "World");
add_word_to_word_list(myWords, "Goodbye");
char** iter;
for (iter = word_list_start(myWords); iter != word_list_end(myWords); ++iter) {
printf("%s ", *iter);
}
delete_word_list(myWords);
return 0;
}
Answer from Tom on Stack OverflowYou've tagged this as C++ as well as C.
If you're using C++ things are a lot easier. The standard template library has a template called vector which allows you to dynamically build up a list of objects.
#include <stdio.h>
#include <vector>
typedef std::vector<char*> words;
int main(int argc, char** argv) {
words myWords;
myWords.push_back("Hello");
myWords.push_back("World");
words::iterator iter;
for (iter = myWords.begin(); iter != myWords.end(); ++iter) {
printf("%s ", *iter);
}
return 0;
}
If you're using C things are a lot harder, yes malloc, realloc and free are the tools to help you. You might want to consider using a linked list data structure instead. These are generally easier to grow but don't facilitate random access as easily.
#include <stdio.h>
#include <stdlib.h>
typedef struct s_words {
char* str;
struct s_words* next;
} words;
words* create_words(char* word) {
words* newWords = malloc(sizeof(words));
if (NULL != newWords){
newWords->str = word;
newWords->next = NULL;
}
return newWords;
}
void delete_words(words* oldWords) {
if (NULL != oldWords->next) {
delete_words(oldWords->next);
}
free(oldWords);
}
words* add_word(words* wordList, char* word) {
words* newWords = create_words(word);
if (NULL != newWords) {
newWords->next = wordList;
}
return newWords;
}
int main(int argc, char** argv) {
words* myWords = create_words("Hello");
myWords = add_word(myWords, "World");
words* iter;
for (iter = myWords; NULL != iter; iter = iter->next) {
printf("%s ", iter->str);
}
delete_words(myWords);
return 0;
}
Yikes, sorry for the worlds longest answer. So WRT to the "don't want to use a linked list comment":
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char** words;
size_t nWords;
size_t size;
size_t block_size;
} word_list;
word_list* create_word_list(size_t block_size) {
word_list* pWordList = malloc(sizeof(word_list));
if (NULL != pWordList) {
pWordList->nWords = 0;
pWordList->size = block_size;
pWordList->block_size = block_size;
pWordList->words = malloc(sizeof(char*)*block_size);
if (NULL == pWordList->words) {
free(pWordList);
return NULL;
}
}
return pWordList;
}
void delete_word_list(word_list* pWordList) {
free(pWordList->words);
free(pWordList);
}
int add_word_to_word_list(word_list* pWordList, char* word) {
size_t nWords = pWordList->nWords;
if (nWords >= pWordList->size) {
size_t newSize = pWordList->size + pWordList->block_size;
void* newWords = realloc(pWordList->words, sizeof(char*)*newSize);
if (NULL == newWords) {
return 0;
} else {
pWordList->size = newSize;
pWordList->words = (char**)newWords;
}
}
pWordList->words[nWords] = word;
++pWordList->nWords;
return 1;
}
char** word_list_start(word_list* pWordList) {
return pWordList->words;
}
char** word_list_end(word_list* pWordList) {
return &pWordList->words[pWordList->nWords];
}
int main(int argc, char** argv) {
word_list* myWords = create_word_list(2);
add_word_to_word_list(myWords, "Hello");
add_word_to_word_list(myWords, "World");
add_word_to_word_list(myWords, "Goodbye");
char** iter;
for (iter = word_list_start(myWords); iter != word_list_end(myWords); ++iter) {
printf("%s ", *iter);
}
delete_word_list(myWords);
return 0;
}
If you want to dynamically allocate arrays, you can use malloc from stdlib.h.
If you want to allocate an array of 100 elements using your words struct, try the following:
words* array = (words*)malloc(sizeof(words) * 100);
The size of the memory that you want to allocate is passed into malloc and then it will return a pointer of type void (void*). In most cases you'll probably want to cast it to the pointer type you desire, which in this case is words*.
The sizeof keyword is used here to find out the size of the words struct, then that size is multiplied by the number of elements you want to allocate.
Once you are done, be sure to use free() to free up the heap memory you used in order to prevent memory leaks:
free(array);
If you want to change the size of the allocated array, you can try to use realloc as others have mentioned, but keep in mind that if you do many reallocs you may end up fragmenting the memory. If you want to dynamically resize the array in order to keep a low memory footprint for your program, it may be better to not do too many reallocs.
c - How to dynamically allocate a structure array? - Stack Overflow
Dynamically Allocated Memory in Structure Array (in C) - Stack Overflow
Dynamic array of structures - C++ Forum
pointers - How to include a dynamic array INSIDE a struct in C? - Stack Overflow
Videos
Hi all! I am very new to C but am familiar with Python & Go quite a bit. Memory allocation is a new concept to me, but I want to start with best practices.
Lets say I want to create a struct that has some members, where one of them happens to be a pointer which I will size dynamically as an array.
Here is what I am doing in my init_my_struct(int n) function. I want to understand if I am doing something that is bad practice here
#include <stdlib.h>
#include <stdio.h>
struct my_struct {
int n;
int *my_arr; // this will be dynamically grown based on user arg
};
struct my_struct * init_my_struct(int n)
{
// allocate memory for one struct
struct my_struct *ms = malloc(sizeof(struct my_struct));
// use -> syntax since ms is a pointer
ms->n = n;
ms->my_arr = malloc(sizeof(int)*n);
return ms;
}
int main(int argc, char *argv[])
{
if (argc < 2) return 1;
int n = atoi(argv[1]);
// initialize the struct members
struct my_struct *ms = init_my_struct(n);
// check out contents of my struct
printf("my struct's n: %d\n", ms->n);
printf("my struct's my_arr: \n");
for (int i = 0; i < n; i++) {
printf("%d\n", ms->my_arr[i]);
}
free(ms); // clean up the memory
return 0;
}Any pointers or tips would be great! Thank you!
Right now, each of your albums has a single track, and the track name is expected to be a single character, instead of what you probably want, a character array.
You're already allocating your albums correctly, but you need to allocate the tracks of each album, too.
The simplest way to do this would be to just specify a fixed number of tracks as a maximum, and just make sure your other code doesn't exceed that.
const int MAX_TRACKS = 20;
const int MAX_HITS = 20;
const int MAX_TRACK_NAME_LENGTH = 63;
struct track_{
char tracks_title[MAX_TRACK_NAME_LENGTH+1];
int playlist_hits[MAX_HITS];
int playlist_hits_count;
};
struct album_ {
int num_tracks;
struct track_ tracks[MAX_TRACKS];
};
Alternatively, you could dynamically allocate the tracks and the track names to the exact sizes needed if you had that information handy. For example, say you were just making a copy of an existing array of albums:
struct track_ {
char *track_title;
int *playlist_hits;
int playlist_hits_count;
};
struct album_ {
int num_tracks;
struct track_ *tracks;
};
typedef struct album_ album;
typedef struct track_ track;
album *copy_albums(album *all_albums_p, int number_of_album) {
album *all_albums_copy = (album *)malloc(sizeof(album) * number_of_album);
// copy each album
for (int album_i = 0; album_i < number_of_album; album_i++) {
album * current_album = all_albums_p + album_i;
album * copy_album = all_albums_copy + album_i;
copy_album->num_tracks = current_album->num_tracks;
copy_album->tracks = (track *)malloc(sizeof(track) * current_album->num_tracks);
// copy each track, and it's hits, and make a new copy of it's name
for (int track_i = 0; track_i < current_album->num_tracks; track_i++) {
track * current_track = current_album->tracks + track_i;
track * copy_track = copy_album->tracks + track_i;
copy_track->playlist_hits_count = current_track->playlist_hits_count;
copy_track->playlist_hits = (int *)malloc(sizeof(int) * current_track->playlist_hits_count);
memcpy(copy_track->playlist_hits, current_track->playlist_hits, current_track->playlist_hits_count * sizeof(int));
copy_track->track_title = _strdup(current_track->track_title);
}
}
return all_albums_copy;
}
typedef struct tracks_{
char tracks_title[101];
int playlist_hits;
} tracks;
typedef struct album_ {
int num_tracks;
struct tracks_ tracks[20];
} album;
album *all_albums_p = (album *)malloc(sizeof(album)*number_of_album);
would allocate number_of_albums times an album with a fixed maximum 20 tracks per album.
If you are using pointer to read and print the struct values then no need of array.If you are trying to use array then this is the way to do it.
#include <stdio.h>
# include <string.h>
# include <stdlib.h>
int main (void)
{
struct student
{
char initial [21];
int age;
float id;
char grade [3];
} list[5];
struct student *tag = ( struct student * ) malloc ( sizeof ( struct student ) * 5);
int i;
for(i=0;i<5;i++)
{
printf("Enter the student initial\n");
scanf("%s",list[i].initial);
printf("Enter the student age\n");
scanf("%d",&list[i].age);
printf("Enter the student id\n");
scanf("%f",&list[i].id);
printf("Enter the grade\n");
scanf("%s",list[i].grade);
tag++;
}
int n;
for ( n = 0; n < 5; n++ ) {
printf ( "%s is %d, id is %f, grade is %s \n",
list [ n ].initial, list [ n ].age, list [ n ].id, list [ n ].grade);
}
return 0;
}
Try this.... Here i am declaring one structure pointer tag. I am allocating memory for 5 student structure . After assigning values ,now tag is pointing to last value.so i decremented it 5 times.This program is using only one pointer. If you want you can try using array of pointer.
I mentioned changes ,in program,as //changes
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
int main (void)
{
struct student
{
char initial [21];
int age;
float id;
char grade [3];
} list[5];
struct student * tag;
tag = ( struct student * ) malloc (5* sizeof (struct student));//changes
strcpy(tag->initial, "KJ");
tag->age = 21;
tag->id = 1.0;
strcpy (tag->grade, "A");
tag++;
strcpy(tag->initial, "MJ");
tag->age = 55;
tag->id = 1.1;
strcpy (tag->grade, "B");
tag++;
strcpy(tag->initial, "CJ");
tag->age = 67;
tag->id = 1.2;
strcpy (tag->grade, "C");
tag++;
strcpy(tag->initial, "SJ");
tag->age = 24;
tag->id = 1.3;
strcpy (tag->grade, "D");
tag++;
strcpy(tag->initial, "DJ");
tag->age = 27;
tag->id = 1.4;
strcpy (tag->grade, "F");
tag++;
int n;
tag=tag-5;//changes
for ( n = 0; n < 5; n++ ) {
printf ( "%s is %d, id is %f, grade is %s\n",
tag->initial, tag->age, tag->id, tag->grade);
tag++;//changes
}
return 0;
}
Using array of pinter...(Instead of using separate assignment, you can use loop for assigning values to every student)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void)
{
struct student
{
char initial [21];
int age;
float id;
char grade [3];
} list[5];
struct student *tag[5];
int i;
for(i=0;i<5;i++)
tag[i]= ( struct student * ) malloc (sizeof (struct student));
strcpy(tag[0]->initial, "KJ");
tag[0]->age = 21;
tag[0]->id = 1.0;
strcpy (tag[0]->grade, "A");
strcpy(tag[1]->initial, "MJ");
tag[1]->age = 55;
tag[1]->id = 1.1;
strcpy (tag[1]->grade, "B");
strcpy(tag[2]->initial, "CJ");
tag[2]->age = 67;
tag[2]->id = 1.2;
strcpy (tag[2]->grade, "C");
strcpy(tag[3]->initial, "SJ");
tag[3]->age = 24;
tag[3]->id = 1.3;
strcpy (tag[3]->grade, "D");
strcpy(tag[4]->initial, "DJ");
tag[4]->age = 27;
tag[4]->id = 1.4;
strcpy (tag[4]->grade, "F");
for ( i = 0; i < 5; i++ )
{
printf ( "%s is %d, id is %f, grade is %s\n",
tag[i]->initial, tag[i]->age, tag[i]->id, tag[i]->grade);
}
return 0;
}
The way you have it written now , used to be called the "struct hack", until C99 blessed it as a "flexible array member". The reason you're getting an error (probably anyway) is that it needs to be followed by a semicolon:
#include <stdlib.h>
struct my_struct {
int n;
char s[];
};
When you allocate space for this, you want to allocate the size of the struct plus the amount of space you want for the array:
struct my_struct *s = malloc(sizeof(struct my_struct) + 50);
In this case, the flexible array member is an array of char, and sizeof(char)==1, so you don't need to multiply by its size, but just like any other malloc you'd need to if it was an array of some other type:
struct dyn_array {
int size;
int data[];
};
struct dyn_array* my_array = malloc(sizeof(struct dyn_array) + 100 * sizeof(int));
Edit: This gives a different result from changing the member to a pointer. In that case, you (normally) need two separate allocations, one for the struct itself, and one for the "extra" data to be pointed to by the pointer. Using a flexible array member you can allocate all the data in a single block.
You need to decide what it is you are trying to do first.
If you want to have a struct with a pointer to an [independent] array inside, you have to declare it as
struct my_struct {
int n;
char *s;
};
In this case you can create the actual struct object in any way you please (like an automatic variable, for example)
struct my_struct ms;
and then allocate the memory for the array independently
ms.s = malloc(50 * sizeof *ms.s);
In fact, there's no general need to allocate the array memory dynamically
struct my_struct ms;
char s[50];
ms.s = s;
It all depends on what kind of lifetime you need from these objects. If your struct is automatic, then in most cases the array would also be automatic. If the struct object owns the array memory, there's simply no point in doing otherwise. If the struct itself is dynamic, then the array should also normally be dynamic.
Note that in this case you have two independent memory blocks: the struct and the array.
A completely different approach would be to use the "struct hack" idiom. In this case the array becomes an integral part of the struct. Both reside in a single block of memory. In C99 the struct would be declared as
struct my_struct {
int n;
char s[];
};
and to create an object you'd have to allocate the whole thing dynamically
struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s);
The size of memory block in this case is calculated to accommodate the struct members and the trailing array of run-time size.
Note that in this case you have no option to create such struct objects as static or automatic objects. Structs with flexible array members at the end can only be allocated dynamically in C.
Your assumption about pointer aritmetics being faster then arrays is absolutely incorrect. Arrays work through pointer arithmetics by definition, so they are basically the same. Moreover, a genuine array (not decayed to a pointer) is generally a bit faster than a pointer object. Pointer value has to be read from memory, while the array's location in memory is "known" (or "calculated") from the array object itself.