Re-sizing dynamically allocated arrays - c

I have written the following code to resize an array if the an item is going to go out of range when storing it. This code works as intended.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//! Our location struct for storing locations
struct location
{
char loc_name[35];
char description[85];
float latitude;
float longitude;
};
void runMenu();
void add_location(struct location** p_location_array, int* p_array_size, int* p_current_size);
void resize_array(struct location** p_location_array, int* p_array_size);
void print (struct location* p_array, int p_current_size);
// Print out the main menu to the user.
void runMenu()
{
printf("[A]dd additional Locations\n");
printf("[P]rint the current list of locations\n");\
printf("[Q]uit the program\n");
}
//! Resize the array to two times it's origional size.
void resize_array(struct location** p_location_array, int* p_array_size)
{
// Allocate enough space for two times the size of the array
int new_size = 2 * (*p_array_size);
struct location* new_location_array = malloc(new_size * sizeof(struct location));
if (!new_location_array)
{
printf ("Cannot add more elements heap has exhausted all space\n");
exit(1);
}
// Copy the old array to the new array.
memcpy(new_location_array, *p_location_array, ((*p_array_size ) * sizeof(struct location)));
// We will update the current size of the array for later checking.
*p_array_size = 2 * (*p_array_size);
// We have a copy of the old array so we can free it.
free(*p_location_array);
// The contents of the pointer reference get the array we malloced in this function
*p_location_array = new_location_array;
}
//! Add a new location to our array. If the array isn't large enough resize it then insert the new struct.
void add_location(struct location** p_location_array, int* p_array_size, int* p_current_size )
{
// Get the users input
struct location new_location;
printf("Enter the new location name\n ");
fscanf(stdin, "%s", new_location.loc_name);
printf("Enter a description of the location\n");
fscanf(stdin, "%s", new_location.description),
printf("Enter the latitude\n");
fscanf(stdin, "%f", &new_location.latitude);
printf("Enter the longitude\n");
fscanf(stdin, "%f", &new_location.longitude);
// Check to see if the size is correct.
if (*p_array_size <= *p_current_size)
{
// If not the correct size resize the array
resize_array(p_location_array, p_array_size);
}
// Insert our sruct
(*p_location_array)[*p_current_size] = new_location;
}
//! Loop over and print out the locations
void print (struct location* p_array, int p_current_size)
{
int i;
for (i = 0; i < p_current_size; i++)
{
struct location current = p_array[i];
printf("%s : %s : %f : %f\n", current.loc_name, current.description, current.latitude, current.longitude);
}
}
int main()
{
char choice = ' ';
short control = 1;
int size;
int currentSize = 0;
printf("Enter the inital size of the array\n");
scanf(" %d", &size);
// Make a new struct array from the heap
struct location* m_location_array =
malloc(size * sizeof(struct location));
// Make sure we have a valid chunk of the heap.
if (!m_location_array)
exit(1);
while(control)
{
runMenu();
scanf(" %c", &choice);
switch (choice)
{
case 'a':
case 'A':
// Do Add additional
add_location(&m_location_array, &size, &currentSize);
currentSize++;
break;
case 'p':
case 'P':
// Do printing
print (m_location_array, currentSize);
break;
case 'Q':
case 'q':
control = 0;
break;
default:
printf("Invalid input\n");
}
}
// clean up after ourselves.
free (m_location_array);
return 0;
}
However, when I originally wrote this function I thought it would be possible to just pass in a the pointer to the array instead of a reference to the pointer like so:
void resize_array(struct location* p_location_array, int* p_array_size)
Calling this function without the reference to pointer threw a segfault indicating the memory was being doubly freed. Is that because the pointer when passed to the function someway gets freed and reallocated? Furthermore, why is it necessary to pass a pointer by reference like this? Even if the pointer is a copy of the original pointer wouldn't it still point to the same piece of memory? Any points in the correct direction is much appreciated.

You gave a pointer to the function and you have a call to free there. So the memory is freed. After that using that pointer causes undefined behaviour and you may not use it.
Modifying the pointer variable inside the function doesn't change the pointer outside the function. That is why you need a pointer to the pointer so that you can modify the pointer variable outside the function.
Even if the pointer is a copy of the original pointer wouldn't it still point to the same piece of memory?
Yes, and that is the point: it will keep on pointing to the same place unless you change it. If you do a new malloc it will point to a completely different place.
Also a hint: realloc might be worth checking out.

If you pass pointer to function it is a copy of original one. Then even if you assign to this pointer inside the function, like
p_location_array = new_location_array;
the original pointer (that outside the function) still has unchanged value. So in case the original pointer pointed to some memory area and you have passed it to the function
void resize_array(struct location *p_location_array, int* p_array_size)
and you have called free() inside thefunction and assigned NULL to the pointer, after your function has returned the original pointer will comapre as not NULL.
// warning, changed prototype
void resize_array(struct location *p_location_array, int* p_array_size);
struct location *loc = malloc(size * sizeof(struct location)); // assume loc = 0x12345678
if (loc == NULL) EXIT_FAILURE;
// change pointer inside the function
// assign NULL to the pointer
resize_array(loc, size_p);
if (loc != NULL)
free(loc); // this will be called, loc is still 0x12345678,
// double free, UB

Related

C adding to struct pointer array doesnt work in function

I have a struct Student. I initialise it inside the main function, and i try to add students inside a function. It doesn't work, but if i put the same code into the main function, it works normally. What am i doing wrong?
struct Student
{
char* name;
};
void addStudent(struct Student *student, int *n)
{
(*n)++;
if(*n != 1)
{
student = realloc(student, (*n) * sizeof(struct Student));
}
printf("Insert name : ");
student[*n-1].name = malloc(25 * sizeof(char));
scanf("%s", student[*n-1].name);
for(int i=0;i<*n;i++)
{
printf("name: %s\n", student[i].name);
}
}
main:
int main() {
int n=0;
struct Student *student = malloc(1 * sizeof(struct Student));
while(1)
{
addStudent(student, &n);
}
}
tl;dr: You need your argument to be of struct Student ** since you are using malloc()/realloc() inside a function.
As you are aware, when an argument is passed in a function, its value is copied so that any changes made inside the function will not be visible to the calling code. We overcome this by passing a pointer to the value we want to modify: we do not change the actual value of our argument, we are only messing with the memory location our pointer argument points to.
In your code, you are reallocating space inside your function, which means that the value of the pointer itself is modified. So, this change is "discarded" after the end of the function and your main never sees the reallocated pointer (note that the allocated space is still "there", meaning that your program takes that resource, you have just no pointer referencing it after the end of your function which is a memory leak).
The solution: make the argument of type pointer to the pointer you want to reallocate, i.e. struct Student **.
The changes you need to do are the following:
void addStudent(struct Student **pstudent, int *n) {
(*n)++;
if(*n != 1){
*pstudent = realloc(*pstudent, (*n) * sizeof(struct Student));
}
(*pstudent)[*n-1].name = malloc(25 * sizeof(char));
scanf("%s", (*pstudent)[*n-1].name);
for(int i=0;i<*n;i++)
{
printf("name: %s\n", (*pstudent)[i].name);
}
}
and in your main() just call your function as:
addStudent(&student, &n);

C program crashes when accessing next element in array of struct

void struct_tokens(struct Words **w_count, int size)
{
*w_count = (struct Words*)calloc(size, sizeof(struct Words));
char *temp;
int n = 0;
int i = 0;
printf("Value 1: %s\n", (*w_count[0]).word);
printf("Value 2: %s\n", (*w_count[1]).word);
}
My struct looks like this:
struct Words
{
char word[20];
unsigned int count;
};
It crashes as soon as I access the next element in the array, so w_count[0] is accessed but it cannot access w_count[1] without crashing. So the Value 1 prints to console but Value 2 does not, why is this?
The calloc call is wrong - it would be
*w_count = calloc(size, sizeof(struct Words));
Accessing the instance of the structure would be
printf("Value 1: %s\n", (*w_count)[0].word);
[] has higher precedence than *. In earlier case you were having undefined behavior (which lead to the crash).
Also note that the memory allocated will be initialized with 0. As a result the char arrays will contain nothing other than \0 - it won't print anything when used in printf.
Few points:
void* to struct Words * conversion is done implicitly - you don't need to cast it.
Check the return value of calloc in case it returns NULL you should handle it appropriately.
Free the dynamically allocated memory when you are done working with it. (using free() ).
Code wise the correct code for calloc would be like this:-
*w_count = calloc(size, sizeof(struct Words));
if( *w_count == NULL ){
perror("calloc");
exit(EXIT_FAILURE);
}

I cannot read string after realloc

I have this function, I realocate memory, but when i want to read string it doesn't work=>error
Student is a Struct
void insertStudent(Student **myStudents, int *size)
{
int newSize = *size + 1;
*myStudents = (Student*)realloc(myStudents, newSize*sizeof(Student));
printf("Enter your grade: ");
scanf("%f", &(*myStudents)[*size - 1].nota);
printf("Enter your first name: ");
scanf("%s", &(*myStudents)[newSize-1].firstName);
printf("Enter your second name: ");
scanf("%s", &(*myStudents)[*size - 1].lastName);
//Generate a new code
/*int code = rand() % 1+1000;
int ok = 0;
while (ok == 0)
{
ok = 1;
for (int i = 0; i < *size; i++)
if ((*myStudents)[i].cod == code)
{
code = rand() % 1 + 1000;
ok = 0;
}
}*/
(*myStudents)[*size-1].cod = 7;
printf("Your code is: %d. Do not forget it! ", 7);
}
void insertStudent(Student **myStudents, int *size)
{
*myStudents = (Student*)realloc(myStudents, newSize*sizeof(Student));
// ^ <- look here
This is a pointer to a pointer to your students. realloc() expects the pointer to the data originally allocated, so you most certainly have to pass *myStudents here!
Also change the code to use a temporary variable. realloc() may return NULL on error, in which case the original memory is still allocated and you have to free() it.
For calculating the size, it's better to use the expression syntax of sizeof (newSize * sizeof **myStudents) because this prevents errors when later changing the type.
For sizes, you should always use size_t, as this is guaranteed to hold any possible size of an object (int is not ...)
Further side note: converting to and from void * is implicit in C and it's arguably better style not to write this cast explicitly.
All in all, the code should be written like this
void insertStudent(Student **myStudents, size_t *size)
{
size_t newSize = *size + 1;
Student *newStudents = realloc(*myStudents, newSize * sizeof *newStudents);
if (!newStudents)
{
free(*myStudents);
*myStudents = 0;
return; // check for this error in calling code
}
*myStudents = newStudents;
*size = newSize;
// [...]
}
realloc() needs pointer to the memory to be reallocated which is *myStudents and not myStudents.
Change
*myStudents = (Student*)realloc(myStudents, newSize*sizeof(Student));
to
*myStudents = (Student*)realloc(*myStudents, newSize*sizeof(Student));
You are reallocting to myStudents. It is not your intention and it is not possible.
From standard 7.22.3.5
void *realloc(void *ptr, size_t size);
Otherwise, if ptr does not match a pointer earlier returned by a
memory management function, or if the space has been deallocated by a
call to the free or realloc function, the behavior is undefined. If
memory for the new object cannot be allocated, the old object is not
deallocated and its value is unchanged.
Earlier you had undefined behavior, you didn't pass the originally allocated memory's address. Rather you passed a local variable. You had undefined behavior.
Student* t = realloc(*myStudents, newSize*sizeof(Student))
if(t){
*myStudents = t;
(*size)++;
}
else {
perror("realloc failed");
free(*myStudents);
exit(EXIT_FAILURE);
}
Also as you are increasing the memory you should do increase it if the call is successful. Then consistently access *size-1 throughout the code, it is easier to handle and go through.
The right way to do it shown above. In case realloc returns NULL you won't lose the reference to the already allocated memory. Also with this comes the advise to check the return value of realloc. Casting is redundant in this case - don't do it.
In the scanf you can simply write
scanf("%s",(*myStudents)[newSize-1].firstName);
otherwise you were passing char (*)[] it expects char*.

Significance of double pointer and triple pointer in this code snippet

#include<stdio.h>
#include<stdlib.h>
void add(char **p);
void print(char **p);
int cnt=0;
main()
{
int option;
char **p=NULL;
while(1)
{
printf("------MENU-----\n");
printf("1>input\n 2>print\n3>exit\n");
printf("enter ur choice\n");
scanf("%d",&option);getchar();
switch(option)
{
case 1: add(p);
break;
case 2: print(p);
break;
case 3: return;
default: printf("Invalid option\n");
}
}
}
void add(char **p)
{
int i;
p=(char**)realloc(p,(cnt+1)*sizeof(char*));
if(p==NULL)
{
printf("Error: memory not available\n");
return;
}
p[cnt]=NULL;
p[cnt]=(char*)realloc(p[cnt],20*sizeof(char));
puts("enter a name");
gets(p[cnt]);
cnt++;
printf("cnt=%d\n",cnt);
}
void print(char **p)
{
int i;
for(i=0;i<cnt;i++)
printf("p[%d]=%s\n",i,p[i]);
}
In the above code, I am making a database of names. For this I am using dynamic memory allocation. I am allocation memory for 2D-array using array of pointers method. When I am executing this program on gcc compiler, I am getting segmentation fault. I am not understanding why is it happening?Could you please tell me where the bug is?
In main, all you do is to assign p = NULL and then use this NULL pointer in print, which causes the segfault. Note that add(p) is equivalent to add(NULL) and does not change p.
Did you mean to pass an address with add(&p)? If so, you need to fiddle a bit with the number of *.
p in main is handed over to add by value. add modifies a local copy then, but not the original p.
Besides the terrible formatting and everything you need to hand a pointer to your main's p to add:
...
case 1: add(&p);
...
void add(char ***p)
{
int i;
*p = realloc(*p,(cnt+1)*sizeof(char*));
if(*p==NULL)
{
printf("Error: memory not available\n");
return;
}
(*p)[cnt]=NULL;
(*p)[cnt]=realloc((*p)[cnt],20*sizeof(char));
puts("enter a name");
gets((*p)[cnt]);
cnt++;
printf("cnt=%d\n",cnt);
}
A copy of 2D pointer p is created in the add function, and updating this pointer will not be reflected in the main function.
A quick solution to this problem is to return the 2D pointer 'p' from the add function.
char** print(char **p)
{
....
....
return p;
}
Pass by reference. You need to pass the address of your pointer to make sure the changes in function add() is reflected in main(). Avoid using gets()
In this case
add(&p);
Accordingly your add() function definition should change to handle this.
Or the other way is for the add function to make the required allocations and return that address to your pointer
char **add();
Check the code below:
char **add(char **p)
{
int i;
p=(char**)realloc(p,(cnt+1)*sizeof(char*));
if(p==NULL)
{
printf("Error: memory not available\n");
return;
}
p[cnt]=NULL;
p[cnt]=(char*)realloc(p[cnt],20*sizeof(char));
scanf("%s",p[cnt]);
cnt++;
printf("cnt=%d\n",cnt);
return p;
}
So your call should be:
p = add(p);
Apart from the other things, I don't think anyone's mentioned the realloc trap of reallocation failure. Suppose this call
p=(char**)realloc(p,(cnt+1)*sizeof(char*));
fails to allocate the new memory: what happens then? Yes, you will get NULL returned: but the memory which was allocated, and which pis pointing to, does not get free'd. Instant memory leak.
You must call realloc like this:
char* pTemp = realloc(p, cnt + 1);
if(pTemp != NULL)
{
p = pTemp; // Now safe to update p
}
else
{
// Error handling as required, possibly including freeing p
}
Yet another reason not to use realloc. It doesn't really by you very much over doing the buffer copies yourself IMHO.

C Dynamically creating array of structs which include variable sized 2d array [duplicate]

I know how to create an array of structs but with a predefined size. However is there a way to create a dynamic array of structs such that the array could get bigger?
For example:
typedef struct
{
char *str;
} words;
main()
{
words x[100]; // I do not want to use this, I want to dynamic increase the size of the array as data comes in.
}
Is this possible?
I've researched this: words* array = (words*)malloc(sizeof(words) * 100);
I want to get rid of the 100 and store the data as it comes in. Thus if 76 fields of data comes in, I want to store 76 and not 100. I'm assuming that I don't know how much data is coming into my program. In the struct I defined above I could create the first "index" as:
words* array = (words*)malloc(sizeof(words));
However I want to dynamically add elements to the array after. I hope I described the problem area clearly enough. The major challenge is to dynamically add a second field, at least that is the challenge for the moment.
I've made a little progress however:
typedef struct {
char *str;
} words;
// Allocate first string.
words x = (words) malloc(sizeof(words));
x[0].str = "john";
// Allocate second string.
x=(words*) realloc(x, sizeof(words));
x[1].FirstName = "bob";
// printf second string.
printf("%s", x[1].str); --> This is working, it's printing out bob.
free(x); // Free up memory.
printf("%s", x[1].str); --> Not working since its still printing out BOB even though I freed up memory. What is wrong?
I did some error checking and this is what I found. If after I free up memory for x I add the following:
x=NULL;
then if I try to print x I get an error which is what I want. So is it that the free function is not working, at least on my compiler? I'm using DevC??
Thanks, I understand now due to:
FirstName is a pointer to an array of char which is not being allocated by the malloc, only the pointer is being allocated and after you call free, it doesn't erase the memory, it just marks it as available on the heap to be over written later. – MattSmith
Update
I'm trying to modularize and put the creation of my array of structs in a function but nothing seems to work. I'm trying something very simple and I don't know what else to do. It's along the same lines as before, just another function, loaddata that is loading the data and outside the method I need to do some printing. How can I make it work? My code is as follows:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
typedef struct
{
char *str1;
char *str2;
} words;
void LoadData(words *, int *);
main()
{
words *x;
int num;
LoadData(&x, &num);
printf("%s %s", x[0].str1, x[0].str2);
printf("%s %s", x[1].str1, x[1].str2);
getch();
}//
void LoadData(words *x, int * num)
{
x = (words*) malloc(sizeof(words));
x[0].str1 = "johnnie\0";
x[0].str2 = "krapson\0";
x = (words*) realloc(x, sizeof(words)*2);
x[1].str1 = "bob\0";
x[1].str2 = "marley\0";
*num=*num+1;
}//
This simple test code is crashing and I have no idea why. Where is the bug?
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;
}
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.
This looks like an academic exercise which unfortunately makes it harder since you can't use C++. Basically you have to manage some of the overhead for the allocation and keep track how much memory has been allocated if you need to resize it later. This is where the C++ standard library shines.
For your example, the following code allocates the memory and later resizes it:
// initial size
int count = 100;
words *testWords = (words*) malloc(count * sizeof(words));
// resize the array
count = 76;
testWords = (words*) realloc(testWords, count* sizeof(words));
Keep in mind, in your example you are just allocating a pointer to a char and you still need to allocate the string itself and more importantly to free it at the end. So this code allocates 100 pointers to char and then resizes it to 76, but does not allocate the strings themselves.
I have a suspicion that you actually want to allocate the number of characters in a string which is very similar to the above, but change word to char.
EDIT: Also keep in mind it makes a lot of sense to create functions to perform common tasks and enforce consistency so you don't copy code everywhere. For example, you might have a) allocate the struct, b) assign values to the struct, and c) free the struct. So you might have:
// Allocate a words struct
words* CreateWords(int size);
// Assign a value
void AssignWord(word* dest, char* str);
// Clear a words structs (and possibly internal storage)
void FreeWords(words* w);
EDIT: As far as resizing the structs, it is identical to resizing the char array. However the difference is if you make the struct array bigger, you should probably initialize the new array items to NULL. Likewise, if you make the struct array smaller, you need to cleanup before removing the items -- that is free items that have been allocated (and only the allocated items) before you resize the struct array. This is the primary reason I suggested creating helper functions to help manage this.
// Resize words (must know original and new size if shrinking
// if you need to free internal storage first)
void ResizeWords(words* w, size_t oldsize, size_t newsize);
In C++, use a vector. It's like an array but you can easily add and remove elements and it will take care of allocating and deallocating memory for you.
I know the title of the question says C, but you tagged your question with C and C++...
Another option for you is a linked list. You'll need to analyze how your program will use the data structure, if you don't need random access it could be faster than reallocating.
Your code in the last update should not compile, much less run. You're passing &x to LoadData. &x has the type of **words, but LoadData expects words* . Of course it crashes when you call realloc on a pointer that's pointing into stack.
The way to fix it is to change LoadData to accept words** . Thi sway, you can actually modify the pointer in main(). For example, realloc call would look like
*x = (words*) realloc(*x, sizeof(words)*2);
It's the same principlae as in "num" being int* rather than int.
Besides this, you need to really figure out how the strings in words ere stored. Assigning a const string to char * (as in str2 = "marley\0") is permitted, but it's rarely the right solution, even in C.
Another point: non need to have "marley\0" unless you really need two 0s at the end of string. Compiler adds 0 tho the end of every string literal.
For the test code: if you want to modify a pointer in a function, you should pass a "pointer to pointer" to the function. Corrected code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct
{
char *str1;
char *str2;
} words;
void LoadData(words**, int*);
main()
{
words **x;
int num;
LoadData(x, &num);
printf("%s %s\n", (*x[0]).str1, (*x[0]).str2);
printf("%s %s\n", (*x[1]).str1, (*x[1]).str2);
}
void LoadData(words **x, int *num)
{
*x = (words*) malloc(sizeof(words));
(*x[0]).str1 = "johnnie\0";
(*x[0]).str2 = "krapson\0";
*x = (words*) realloc(*x, sizeof(words) * 2);
(*x[1]).str1 = "bob\0";
(*x[1]).str2 = "marley\0";
*num = *num + 1;
}
Every coder need to simplify their code to make it easily understood....even for beginners.
So array of structures using dynamically is easy, if you understand the concepts.
// Dynamically sized array of structures
#include <stdio.h>
#include <stdlib.h>
struct book
{
char name[20];
int p;
}; //Declaring book structure
int main ()
{
int n, i;
struct book *b; // Initializing pointer to a structure
scanf ("%d\n", &n);
b = (struct book *) calloc (n, sizeof (struct book)); //Creating memory for array of structures dynamically
for (i = 0; i < n; i++)
{
scanf ("%s %d\n", (b + i)->name, &(b + i)->p); //Getting values for array of structures (no error check)
}
for (i = 0; i < n; i++)
{
printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures
}
scanf ("%d\n", &n); //Get array size to re-allocate
b = (struct book *) realloc (b, n * sizeof (struct book)); //change the size of an array using realloc function
printf ("\n");
for (i = 0; i < n; i++)
{
printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures
}
return 0;
}
If you want to grow the array dynamically, you should use malloc() to dynamically allocate some fixed amount of memory, and then use realloc() whenever you run out. A common technique is to use an exponential growth function such that you allocate some small fixed amount and then make the array grow by duplicating the allocated amount.
Some example code would be:
size = 64; i = 0;
x = malloc(sizeof(words)*size); /* enough space for 64 words */
while (read_words()) {
if (++i > size) {
size *= 2;
x = realloc(sizeof(words) * size);
}
}
/* done with x */
free(x);
Here is how I would do it in C++
size_t size = 500;
char* dynamicAllocatedString = new char[ size ];
Use same principal for any struct or c++ class.

Resources