I made an array of Node structs and I am trying to sort nodes in alphabetical order based on their char* variable called "word".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memwatch.h"
#include "concord.h"
#define BUFFSIZE 1000
int main(int argc, char** argv)
{
Node** list;
printf("%s%s\n","The file name is ", argv[1]);
readInputFile(argv[1], list);
return 0;
}
int compareWords(const void* nodeA, const void* nodeB)
{
Node* nodeAA = (Node *) nodeA;
Node* nodeBB = (Node *) nodeB;
puts("now here\n");
printf("%s\n", nodeAA->word);
printf("%s\n", nodeBB->word);
return strcmp(nodeAA->word, nodeBB->word);
}
void readInputFile(char* filename, Node** wordList)
{
FILE* file;
file = fopen(filename, "r");
wordList = calloc(BUFFSIZE, sizeof(Node*));
char* currentWord;
currentWord = (char*) malloc(sizeof(char) *BUFFSIZE);
int i;
i = 0;
while(fscanf(file, "%s", currentWord) == 1)
{
wordList[i] = (Node*) malloc(sizeof(Node));
wordList[i]->word = strdup(currentWord);
puts(wordList[i]->word);
}
fclose(file);
qsort(wordList, i, sizeof(Node), compareWords);
}
Before I was printing out garbage when I tried to print out the word in the compare function, now it looks like the function is not even being called.
now it looks like the function is not even being called.
That is because to sort a list of 0 elements you never need to compare two elements:
// ...
int i;
i = 0; // --- set to 0
while(fscanf(file, "%s", currentWord) == 1)
{
// i not changed ... causes other problems, too
// (contents omited)
}
fclose(file);
// i is still 0
qsort(wordList, i, sizeof(Node), compareWords);
// ...
Apart from that your usage of an "out parameters" is wrong, as pointed out in the comment by David C. Rankin. In this case, i'd also advise to just use the return value.
Moreover, I'd split that function into multiple functions:
// Does the file opening and closing, calls readInput
Node * readInputFile(char const *);
// The actual reading
Node * readInput(FILE *)
// Probably do the sorting outside of these functions
[First of all you question is incomplete as it misses to show us the definition of Node.]
However, three issues here:
I made an array of Node structs
You don't.
Here
wordList = calloc(BUFFSIZE, sizeof(Node*));
you allocate memory for an array of pointers to Node.
And then here
wordList[i] = (Node*) malloc(sizeof(Node));
you allocated a separate chunk of memory to each element of the pointer array created previously.
The latter may be scattered all over the process's memory. They will not be located in a continous block of memory, as expected by qsort(), which might have been the reason for:
I was printing out garbage [before]
On returning from readInputFile() the value of wordList is lost.
The reading loop does not increment the index counter i.
To fix 1. and 2. create an array and return a reference to it back up to the caller of readInputFile() like so
*wordList = calloc(BUFFSIZE, sizeof **wordList);
and call qsort() like this:
qsort(*wordList, i, sizeof(Node), compareWords);
To fix 3. do this:
size_t i = 0; /* No need for negative indexes here .*/
while((i < BUFFSIZE) /* Male sure not to overflow the array. */
&& (fscanf(file, "%s", currentWord) == 1))
{
(*wordList)[i].word = strdup(currentWord); /* This is POSIX not Standard C. */
puts((*wordList)[i].word);
++i;
}
Related
I'm writing a program that is supposed to assign characters from a buffer into a hash-table. I ran valgrind on my program and it signals to a particular line (tmp->word = buffer[i];) and keeps telling me there is a segmentation fault there.
I tried hardcoding the problem line to (tmp->word = 'c';) but the compiler rejected that implementation. I checked to see if the buffer array was initialized, which it was. The program compiles when the problem line is changed to (tmp->word = buffer[i];) but that leads back to a segmentation fault. I have also tried printing the character field in my data structure after I assign it, but the segmentation fault occurs before that can happen. This is what I've written so far. Any help would be greatly appreciated.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
struct node* next;
char word;
}
node;
void unload(node* current);
int main(void)
{
node* table[26];
char buffer[5] = "Hello";
printf("%s\n", buffer);
int index = tolower(buffer[0]) - 'a';
node* tmp = table[index];
for(int i = 0, n = strlen(buffer); i < n - 1; tmp = tmp->next)
{
tmp->word = buffer[i];
printf("%c\n", tmp->word);
i++;
}
//follows word that was input
index = tolower(buffer[0]) - 'a';
for(int j = 0; j < 1; j++)
{
tmp = table[index]->next;
unload(tmp);
}
}
void unload(node* current)
{
if (current->next != NULL)
{
unload(current->next);
}
free(current);
}
As was mentioned before in the comments and answer, my array of pointers wasn't initialized. This was a part of the main problem I had which was experiencing a segmentation fault when I tried to assign table[i]->word and table[i]->next a value. No memory was allocated for the nodes in the table so I went and did that which fixed most the problems! Something I learned, however, is that I could not assign a string to table[i]->word which is an array of characters in my now less buggy program, and instead had to use strcpy to read a string into that memory space (please correct me if I'm wrong on that). Thank you all for your help and advice, it was really useful! Posted below is the version of my program that actually works save for a conditional that I need to implement thanks to your guys' help! Again, thank you very much!
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cs50.h>
#define LENGTH 45
#define CAPACITY 26
typedef struct node
{
struct node* next;
char word[LENGTH + 1];
}
node;
int hash(char* current);
void unload(node* current);
int main(void)
{
//const unsigned int N = 26;
node* table[CAPACITY];
for(int i = 0; i < CAPACITY; i++)
{
table[i] = malloc(sizeof(node)); // this was table[i]->next before. I didn't allocate memory for this node and then tried to defrefernce to a field in a node I though existed
if(table[i] == NULL)
{
printf("Could not allocate memory for hashtable node");
for(int j = 0; j < CAPACITY; j++)
{
unload(table[i]);
}
return 1;
}
table[i]->next = NULL; //just reinitializing the value here so that its not a garbage value
//table[i]->word = "NULL";
}
int q = 0;
while(q < 3) //ths will be chnaged so that we're reading from a file into a buffer and that get_string is gone, hash() stays tho
{
char* name = get_string("Here: ");
int index = hash(name);
if(table[index]->next == NULL)
{
node* cursor = malloc(sizeof(node)); //I'm not executing this if the hash code is the same
table[index]->next = cursor;
strcpy(cursor->word, name); //for some reason you can't just assign a value to an element in an array in a data structure, seems that you need to read the data you want to assign into the location of the element
//cursor->word = name;
cursor->next = NULL;
printf("%s\n", cursor->word);
}
q++;
}
for(int i = 0; i < CAPACITY; i++)
{
unload(table[i]); //wonder why I don't need to do table[i]->next? does this not free the hash table after the first iteration?
// the answer to above is because we are only freeing the node which is that element in the array, not the array itself
}
strcpy(table[6]->word, "Zebra");
printf("%lu\n", sizeof(table[6]));
printf("%s\n", table[6]->word);
/*for(int i = 0; i < CAPACITY; i++)
{
unload(table[i]); //only problem here is that it will eventually free the hash table itself after the first linked list
}*/
}
int hash(char* current)
{
int index = tolower(current[0]) - 'a';
return index;
}
void unload(node* current)
{
if (current->next != NULL)
{
unload(current->next);
}
free(current);
}
As is the comments the main problem is an array of uninitialized pointers. As "intuitive way" while you are coding you may think the once you typed node* table[26]; as int type variables, this will be set to NULL automatically as a pattern behavior or something.But it points to a random location in memory when you declare it. It could be pointing into the system stack, or the global variables, or into the program's code space, or into the operating system.
So, you must give them something to point to and in this case is a NULL. You can do it like this node* table[26] = {NULL};. Another point is when you type char buffer[5] = "Hello";. The char buffer[5] essentially is a pointer pointing to a memory address that the system saves so you can put your string. The memory is saved in blocks so when you type char buffer[1] for example you "jump" to the second part of the entire block which represents the string.
When you do char buffer[5] = "Hello"; " it's sounds like " you are trying to make the Hello string fit in the last piece of the block. To fix this just type char buffer[6] = {"Hello"};(Because you need n+1 of size, you have to include the \0 character). And it will fit properly. Now i think you can figure out how to do the rest.
I'm working on a function that works as part of a larger program. My C pointer skills are a bit rusty and so I need some help here.
I keep getting segmentation fault errors, and I feel like there is a very trivial solution to my question, and any explanation would help!
Essentially, I have an empty array of structs that I need to pass through to a function as a double pointer. That function will open and read a file saving the contents of the file in the array of structs.
I need to pass it as a double pointer.
This is what I have so far:
struct node{
int first_value;
int second_value;
};
unsigned char readFunction(char *fileName, int *limit, struct node **arrayToFill){ //Many more variables passed, but I removed it for the sake of simplicity
FILE *input;
input = fopen(fileName, "r");
if (input == NULL) {
printf("error: could not read the input file!\n");
}
int i=0;
int temp1, temp2;
for(i=0; i<(*limit); i++){
fscanf(input, "(%d, %d)", &temp1, &temp2);
(*(arrayToFill+i))->first_value = temp1;
(*(arrayToFill+i))->second_value= temp2;
}
//More code
return 0; //Actually returns another array but that's irrelevant.
}
int main(){
//NOTE: I just created these variables for the sake of showing it on StackOverflow, I still get a Segmentation Fault error when I run the program.
char name[9] = {'t', 'e', 's', 't', '.', 't','x','t', '\0'};
struct node arrayToPass[10];
struct node *pointer = &arrayToPass;
struct node **data = &pointer;
unsigned char returnedVal;
int limit = 10;
returnedVal = readFunction(&name, &limit, data);
return 0;
}
Thanks in advance!
You have several problems. The first is you are using the arrayToPass[10] pointer incorrectly, all you need is:
int main (void) {
struct node arrayToPass[10];
int limit = 10;
printf ("return: %hhu\ncontent:\n", readFunction(NULL, &limit, &arrayToPass));
for (int i = 0; i < limit; i++)
printf ("%5d %5d\n",
arrayToPass[i].first_value, arrayToPass[i].second_value);
}
Do not attempt to cast around your struct node (*arrayToPass)[10] pointer when you pass the address by assigning to different pointers. You begin with type struct node [10] (array of struct node [10]) when you take the address you have struct node (*)[10] (pointer to array of struct node [10]). It is separate and district from struct node ** (pointer to pointer to struct node).
Your function then takes the type struct node (*arrayToFill)[10], e.g.
unsigned char readFunction (char *fileName, int *limit, struct node (*arrayToFill)[10])
{ //Many more variables passed, but I removed it for the sake of simplicity
FILE *input;
input = fileName ? fopen (fileName, "r") : stdin;
if (input == NULL) {
printf("error: could not read the input file!\n");
}
int i=0;
int temp1, temp2;
while (i < *limit && fscanf(input, " (%d, %d)", &temp1, &temp2) == 2) {
(*arrayToFill)[i].first_value = temp1;
(*arrayToFill)[i].second_value = temp2;
i++;
}
*limit = i;
return 0; //Actually returns another array but that's irrelevant.
}
(note: the use of the ternary operator allowing NULL to be passed as fileName to read from stdin -- that was just for my convenience)
(also note: that since you declare struct node arrayToPass[10]; with automatic storage duration in main(), you don't need to pass the address of the pointer, you only need to pass the address of the pointer if the address can changes in your function -- such as if you call realloc on the pointer. The other answer addresses that point.)
The difference between needing to pass struct node ** or struct node (*)[10] or simply struct node * boils down to how memory is allocated for the original collection. If as you have done, declaring struct node arrayToPass[10]; in main() with automatic storage duration, storage for the array is fixed. On access, the array is converted to a pointer (struct node *) and you can simply pass the array itself as the parameter. (but you are limited to no more than the number of elements originally declared)
If however, you have an allocated storage type for arrayToPass in main (e.g. struct node *arrayToPass = malloc (10 * sizeof *arrayToPass);, then if you need to change the amount of storage, e.g. the number of stuct node that your allocated block of memory can hold in readFunction(), then you must pass the address of the pointer, so if reallocation takes place, and the beginning address for your block of memory changes, that change will be seen back in the caller (main() here). In that case when you pass the address of struct node *, then your type becomes struct node **. (because you have taken the address of a pointer instead of the address of an array)
Since your arrayToPass can't be reallocated, and the storage is fixed before it is passed to readFunction(), you don't need to pass the address and you can eliminate one level of pointer indirection and just pass the array as type struct node *. That simplifies access in your function to simply arrayToFill[i].first_value = temp1;, the [..] acting as a dereference of the pointer, just as -> does.
You also may want to change the return type from unsigned char to size_t and return the number of elements filled in your struct (a meaningful return) -- or you can update the limit pointer as I did -- your choice.
The complete example is:
#include <stdio.h>
struct node {
int first_value;
int second_value;
};
unsigned char readFunction (char *fileName, int *limit, struct node (*arrayToFill)[10])
{ //Many more variables passed, but I removed it for the sake of simplicity
FILE *input;
input = fileName ? fopen (fileName, "r") : stdin;
if (input == NULL) {
printf("error: could not read the input file!\n");
}
int i=0;
int temp1, temp2;
while (i < *limit && fscanf(input, " (%d, %d)", &temp1, &temp2) == 2) {
(*arrayToFill)[i].first_value = temp1;
(*arrayToFill)[i].second_value = temp2;
i++;
}
*limit = i;
return 0; //Actually returns another array but that's irrelevant.
}
int main (void) {
struct node arrayToPass[10];
int limit = 10;
printf ("return: %hhu\ncontent:\n", readFunction(NULL, &limit, &arrayToPass));
for (int i = 0; i < limit; i++)
printf ("%5d %5d\n",
arrayToPass[i].first_value, arrayToPass[i].second_value);
}
Example Input File
$ cat dat/2x8rand.txt
(17987, 1576)
(12911, 4488)
(30688, 5875)
(25617, 16643)
(8999, 26249)
(29270, 31857)
(8954, 2094)
(21390, 27676)
Note the change in the fscanf format-string including an additional ' ' (space) before the opening parenthesis '(' to consume the '\n' (and any leading whitespace). You cannot use any input function correctly unless you check the return (e.g. fscanf(input, " (%d, %d)", &temp1, &temp2) == 2)
Example Use/Output
$ ./bin/ptrtoarraystruct < dat/2x8rand.txt
return: 0
content:
17987 1576
12911 4488
30688 5875
25617 16643
8999 26249
29270 31857
8954 2094
21390 27676
Look things over and let me know if you have further questions.
I believe you may want something like the following.
#include <stdio.h>
struct node{
int first_value;
int second_value;
};
unsigned char readFunction(char *fileName, int limit, struct node *arrayToFill){ //Many more variables passed, but I removed it for the sake of simplicity
FILE *input;
input = fopen(fileName, "r");
if (input == NULL) {
printf("error: could not read the input file!\n");
}
int i=0;
int temp1, temp2;
for(i=0; i<limit; i++){
fscanf(input, "(%d, %d)", &temp1, &temp2);
arrayToFill[i].first_value = temp1;
arrayToFill[i].second_value = temp2;
}
//More code
return 0; //Actually returns another array but that's irrelevant.
}
int main(){
//NOTE: I just created these variables for the sake of showing it on StackOverflow, I still get a Segmentation Fault error when I run the program.
char name[9] = "test.txt";
struct node arrayToPass[10];
unsigned char returnedVal;
int limit = 10;
returnedVal = readFunction(name, limit, arrayToPass);
return 0;
}
This problem is similar to mine.
But deliver no solution for me.
This is only a simplified code for testing and better understanding.
I know that this code doesn't care of problems after the malloc functions.
The code is for saving words in a struct called List, within a char** storage that used as array.
To create the list and add an item works fine.
But the deletion of the list makes problems.
Here is the code:
Declaration of the list:
typedef struct {
char** storage;
} List;
Main:
int main(){
int size = 2;
List* list;
list = new_list(2);
add(list, "Hello", 0);
add(list, "World", 1);
printf("\nlist->storage[0]: %s", list->storage[0]);
printf("\nlist->storage[1]: %s", list->storage[1]);
delete_list(&list,size);
return 0;
}
Make a new list:
List* new_list(size) {
List* listptr = malloc(sizeof(List));
listptr->storage = (char**)malloc(size * sizeof(char));
return listptr;
}
Add a string to the list:
void add(List* list, char* string, int pos) {
list->storage[pos] = (char*)malloc(strlen(string) * sizeof(char));
list->storage[pos] = string;
}
Delete the list, with all members:
void delete_list(List** list, int size) {
int a = 0;
for (a = 0; a < size; a++)
free((*list)->storage[a]);
free((*list)->storage);
free(*list);
}
Here I get an error in the for loop, at the line 'free((*list)->storage[a])'.
The goal is here to delete every allocated string.
If the list has no members, therefore the code run not in the for loop and the 'delte_list' function work well.
So that is my mistake in the line:
'free((*list)->storage[a])'
This allocation is wrong:
listptr->storage = (char**)malloc(size * sizeof(char));
^^^^^
As storage is a char** the sizeof should be sizeof(char*). When you only use sizeof(char) you end up with too little memory and later you write outside the allocated memory.
Also this line:
list->storage[pos] = string;
seems wrong.
Here you probably need a strcpy like:
strcpy(list->storage[pos], string)
and also add 1 to the malloc for the string termination, i.e.
malloc((1 + strlen(string)) * sizeof(char));
but notice that sizeof(char) is always 1 so
malloc(1 + strlen(string));
is fine.
BTW: A good way of getting your malloc correct is to use "sizeof what_the_variable_points_to". Like:
char** x = malloc(size * sizeof *x);
^^
Use *x instead of sizeof(char*)
in this way you always get the correct size and avoid bugs due to simple typos.
As an example from your code:
List* listptr = malloc(sizeof(List)); // works but
List* listptr = malloc(sizeof *listptr); // this is less error prone
I want to create function that adds words into dictionary
so far i made this
void addWord(char **dictionary,int *dictionarySize,int *wordsInDictionary,char *word){
if(dictionary == NULL)
{
*dictionary = (char *)malloc(sizeof(char*)*(*dictionarySize));
}
else
{
if(*wordsInDictionary==*dictionarySize)
{
*dictionary = (char *)realloc(dictionary,sizeof(char*)*(*dictionarySize)*2);
(*dictionarySize)*=2;
}
}
dictionary[*wordsInDictionary]=word;
(*wordsInDictionary)++;
}
in main() i have
int i;
int dictSize = 1;
int wordsInDict = 0;
char *word;
char *dictionary;
dictionary=NULL;
then i want to print all words in dictionary , but here i get warning that %s is expecting char* but it is int
printf("Stats: dictsize: %d, words in dict: %d\n", dictSize,wordsInDict);
for(i=0;i<wordsInDict;i++)
{
printf("%d. %s\n",i, dictionary[i]);
}
it also gives me errors when i try to add words
i use this call to add words
addWord(&dictionary,&dictSize,&wordsInDict,word);
In your addWord function, dictionary will never be NULL.
And that's only the start of your problems. Because you want dictionary to be an array of arrays, which mean you need to declare it as a pointer to a pointer (if you want it to be dynamic). However, you declare it as just a (single) pointer. It's in the main function (or where ever you declare it originally) that you need to declare it as a pointer to a pointer. And you need to initialize it, or it will have an indeterminate value and using it in any way other than initializing it will lead to undefined behavior.
That means your addWord function should take a pointer to a pointer to a pointer, i.e. one more level of indirection. And you need to use the dereference operator to get the original pointer to pointer.
So the addWord function should start like e.g.
void addWord(char ***dictionary, int *dictionarySize, int *wordsInDictionary,char *word){
if(*dictionary == NULL)
{
*dictionary = malloc(sizeof(char*) * (*dictionarySize));
}
...
}
Also note that I don't cast the return of malloc.
Also note that realloc can fail, and then will return NULL, so if you assign the return to the same pointer you reallocate you will loose the original pointer. Always use a temporary pointer for the return-value of realloc and only assign to the real pointer after checking that the reallocation succeeded.
I suggest that you put together the members of the dictionary in one as a structure, rather than having individually.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dictionary {
char **words;//array of char *
int size;
int numOfWords;
} Dictionary;
Dictionary *D_new(void){
Dictionary *dic = malloc(sizeof(*dic));
if(dic){
dic->size = 16;//initial size
dic->words = malloc(dic->size * sizeof(*dic->words));//check omitted
dic->numOfWords = 0;
}
return dic;
}
void D_drop(Dictionary *dic){
int i;
for(i=0;i<dic->numOfWords; ++i)
free(dic->words[i]);
free(dic->words);
free(dic);
}
void addWord(Dictionary *dic, const char *word){
if(dic == NULL){
return ;
}
if(dic->numOfWords == dic->size){
dic->words = realloc(dic->words, sizeof(*dic->words)*(dic->size*=2));//check omitted
}
dic->words[dic->numOfWords++]=strdup(word);//make copy
}
int main(void){
int i;
Dictionary *dictionary = D_new();
addWord(dictionary, "apple");
addWord(dictionary, "banana");
addWord(dictionary, "melon");
printf("Stats: dictsize: %d, words in dict: %d\n",
dictionary->size, dictionary->numOfWords);
for(i=0;i<dictionary->numOfWords;i++){
printf("%d. %s\n", i, dictionary->words[i]);
}
D_drop(dictionary);
return 0;
}
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.