Allocating array of struct with array inside - c

I want to read users input combined of strings and numbers, like this:
50:string one
25:string two blablabla
...
I don't know how many of the lines the input will have and I also don't know maximum length of the strings.
So I created
typdedef struct line
{
int a
char *string
} line;
Then an array of this sturct
line *Array = NULL;
Now I have a cycle, that reads one line and parses it to temporaryString and temporaryA. How can I realloc the Array to copy these into the array?

There are two valid options to do what you want:
1) use the realloc() function; it's like malloc and calloc but you can realloc your memory, as the name can advise;
2) use a linked list;
The second is more complex than the first one, but is also really valid. In your case, a simple linked list could have the form:
typdedef struct line
{
int a;
char *string;
line *next;
//line *prev;
} line;
Everytime you add a node, you have to alloc a struct line with your new data, set next pointer to NULL or to itself, it's the same, and set the previous next pointer to the new data you created. That's a simpy method to do manually a realloc. The prev pointer is needed only if you need to go from the last item to the first; if you don't need this feature, just save the root pointer (the first one) and use only next pointer.

You could something like this (pseudo code).
idx = 0;
while (input = read()) {
temporaryString, temporaryA = parse(input);
Array = realloc(Array, (idx + 1)*sizeof(line));
Array[idx].a = temporaryA;
Array[idx].string = malloc(strlen(temporaryString) + 1);
strcpy(Array[idx].string, temporaryString);
idx++;
}

Related

Program Crashes When Accessing array inside Struct

I'm trying to implement the first part of an autocomplete feature that takes in a string, calculates an index for a particular letter, and then allocates another struct pointer at that index. It also stores possible completions of words in a string array. For some reason, the program crashes when I try to access the string array field, and I can't figure out why. How can I fix this?
Thanks
struct table {
struct table *next[26];
char **complete;
int lastIndex;
int size;
};
static struct table Base={{NULL},NULL,0,0};
void insert(const char *string){
int index=string[0]-'a';
if(Base.next[index]==NULL){
Base.next[index]=(struct table*)malloc(sizeof(struct table));
*Base.next[index]=(struct table){{NULL},NULL,0,0};
}
struct table *pointer=Base.next[index];
if(pointer->lastIndex==pointer->size){ //expand complete array
pointer->complete[pointer->lastIndex] = strdup(string); //program crashes here
pointer->lastIndex=pointer->lastIndex+1;
}
}
The crash in this line
pointer->complete[pointer->lastIndex] = strdup(string);
is because pointer->complete is NULL. In other words, you forgot to allocate memory for complete.
How can I fix this?
You must allocate memory. It seems that you want a dynamic sized array of char pointers. So you'll need to use realloc so that you both extend the allocated memory and preserve previous values.
Something like:
char** tmp = realloc(pointer->complete, (pointer->lastIndex + 1) * sizeof(char*));
if (tmp == NULL)
{
// Out of memory
exit(1);
}
pointer->complete = tmp;
// Then you can do your normal code
pointer->complete[pointer->lastIndex] = strdup(string);
Notice: Though it's possible to use realloc every time you insert a string, it may perform rather bad.
So instead of reallocating memory for every new string, it may be better to reallocate a chunk of memory each time you call realloc. Like:
if (pointer->lastIndex == pointer->size)
{
// Need more memory
// - if it's the first time just start with 10 (or another number)
// - else double the size
pointer->size = (pointer->size != 0) ? 2 * pointer->size : 10;
char** tmp = realloc(pointer->complete, (pointer->size) * sizeof(char*));
if (tmp == NULL)
{
// Out of memory
exit(1);
}
pointer->complete = tmp;
}
Here I decided to double the allocated memory when doing realloc. You can of cause use ant approach you like instead, e.g. always add 10 more instead of doubling.
BTW: The name lastIndex seems poor as it's really a nextIndex variable.
A final word on data structure
Your data structur, i.e. struct table seems a bit strange to me. At base-level, you only use table. At the next level you don't use table but only the other variables.
Seems to me that you should split up the struct into two structs like:
struct StringTable {
char **complete;
int lastIndex;
int size;
};
struct table {
struct StringTable strings[26];
};
That would save you both memory and some of the dynamic memory allocation.
You are assuming that
const char * string
will contain only small case alphabets. Dictionaries also have apostrophes
add that case.

adding and printing elements of ** pointer that is controlled by a pointer to a struct

I have a struct typedef to SmartArray that has a variable char **array. I have been trying to debug the code for several hours, and have made lots of progress. However, i'm stuck on this particular bug. I have a function to print said array out. It will print twice, and then on the third time it does not print at all! I have a feeling this has something to do with how I am adding malloc to an array being one one does not print out correct. For the last section of the array, it prints "Testing Na". Any ideas? I would appreciate the help.
Here is the part of the function I am suspecting is the cause, however, I can't seem to find it: //allocate min space for string
printf("approaching malloc\n");
strPtr = malloc( sizeof(char) * (strlen(str) + 1) );
if(strPtr == NULL)
{
return NULL;
}
printf("made it past malloc!\n");
strcpy(strPtr, str);
//if crash probably this code
smarty->array[index] = strPtr;
if(smarty->array[0] == NULL)
{
return NULL;
}
return strPtr;
Here is my test code:
typedef struct SmartArray
{
// We will store an array of strings (i.e., an array of char arrays)
char **array;
// Size of array (i.e., number of elements that have been added to the array)
int size;
// Length of the array (i.e., the array's current maximum capacity)
int capacity;
} SmartArray;
int main(void)
{
int i; char buffer[32];
SmartArray *smarty1 = createSmartArray(-1);
printf("Array created\n");
// Print the contents of smarty1.
printf("\n-- SMART ARRAY 1: --\n");
printSmartArray(smarty1);
printf("Made it past print!\n");
put(smarty1,"Hi, my name is ");
put(smarty1, "Hello, my name is");
put(smarty1, "Testing Names");
printf("made it past put!\n");
printf("smart away is now\n");
printSmartArray(smarty1);
printf("end of main!\n");
I feel like it's something completely obvious I'm just overlooking because I am a novice.
Here's a picture of what i'm trying to get it to look like in memory:
click here for memory diagram
UPDATE: I figured out why it wasn't printing all the names, but the program segfaults atfter the print function.
I think it is because you are trying to extend your array using malloc. A C array can only point to one block of storage at a time. When you use malloc it will allocate an entirely new block of storage and you are trying to add that on to the end of your array when you write smarty->array[index] = strPtr.
If you want to extend the size of your C array, use realloc instead which will allocate a new, bigger block of memory for your array and copy the existing content to it as well.
If that doesn't solve the problem can you post your entire put function?

How can I set a certain value to a member of a struct within multiple functions?

i am a beginner so please cut me some slack on this one. So I have two functions and a struct in a header file I am currently working with.
This is the struct:
typedef struct ArrayList
{
// We will store an array of strings (i.e., an array of char arrays)
char **array;
// Size of list (i.e., number of elements that have been added to the array)
int size;
// Length of the array (i.e., the array's current maximum capacity)
int capacity;
} ArrayList;
Here is the first function, which creates and dynamically allocates memory for an array of strings. Capacity is the length of the internal array and size is the current size (how many strings are in the array which is essentially 0.)
ArrayList *createArrayList(int length){
char **array = NULL;
ArrayList *n;
int size = 0;
if (length > DEFAULT_INIT_LEN)
{
array = malloc(sizeof(int) * length);
n->capacity = length;
}
else
{
array = malloc(sizeof(int) * DEFAULT_INIT_LEN);
n->capacity = DEFAULT_INIT_LEN;
}
if (array == NULL)
panic("ERROR: out of memory in Mylist!\n");
n->size = size;
printf("-> Created new ArrayList of size %d\n", n->capacity);
return *array;
When I try to implement a pointer to the capacity member of the ArrayList struct inside another function within the same file, it is uninitialized instead of set as the value from the previous function. I.e. in createArrayList, n->capacity is equal to 10, but when used in printArrayList it is uninitialized and a random number appears such as 122843753.:
void printArrayList(ArrayList *list)
{
printf("\n%d", list->capacity);
return NULL;
}
My question is, how can I make it so all these functions "share" the same value when referring to the struct members. I.E. the first function prints -> Created new ArrayList of size 10, and the second function prints 10 as well. Also, I have to do this without changing the struct function itself. Sorry if this is a poorly worded question, but I can further clarify if it is confusing. Thanks in advance!
I see a couple of major issues with this code, in createArrayList you are returning array which is a char ** but you should be returning an ArrayList * which is what n is. So it looks like you want to assign array to n->array. The next issue is that n is an ArrayList * but you do not allocate memory for n.

storing data in addresses and changing the address of a variable in C?

Newbie here,
I have a struct for a word, which contains a char array for the words themselves(the struct has other functions, which are unrelated to my question) and I'm trying to store it in a hashmap, which is an array of word struct pointers. In my program, every time I see a new word, I create a new word struct and malloc the char-array to create it. However, after a few run through of the loop, it changes the old word to a new word, even though it's at different hashmap locations.
What I'm wondering is if it's possible to have the loop in which I create the new word struct point to a new address?
struct words add;
int b;
for(b = 0; b < strlen(LowerCaseCopy); b++)
{
add.word[b] = '\0';
}
for(b=0;b< strlen(LowerCaseCopy);b++)
{
add.word[b] = LowerCaseCopy[b];
}
hashmap[hashf] = &add;
This is the code in question.
An example of my problem:
the first runthrough of the loop, I set add.word to apple, which is stored at a specific hashmap slot.
the next runthrough of the loop, I set add.word to orange, which is stored at a different slot. The problem is that at the first slot, it no longer stores apple, it instead stores orange, so I have 2 slots that store orange, which is not what I want. How do I fix this?
A simple solution (I think) would be to put the functionality to add entries to the hashmap in a separate function. This function allocates a new words structure and puts that in the hashmap:
void add_to_hashmap(struct something *hashmap, char *lower_case_word)
{
/* Using "calloc" we don't have to manually clear the structure */
struct words *words = calloc(1, sizeof(struct words));
/* Copy +1 to include the terminating '\0' */
memcpy(words->word, lower_case_word, strlen(lower_case_word) + 1);
/* Replace this with whatever you use to calculate the hash */
int hashf = calculate_hash(lower_case_word);
hashmap[hashf] = words;
}
If you remove an entry (i.e. setting it to NULL) you have to remember to free it first.

Parse values from a text file in C [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Parsing text in C
Say I have written to a text file in this format:
key1/value1
key2/value2
akey/withavalue
anotherkey/withanothervalue
I have a linked list like:
struct Node
{
char *key;
char *value;
struct Node *next;
};
to hold the values. How would I read key1 and value1? I was thinking of putting line by line in a buffer and using strtok(buffer, '/'). Would that work? What other ways could work, maybe a bit faster or less prone to error? Please include a code sample if you can!
Since your problem is a very good candidate for optimizing memory fragmentation, here is an implementation that uses some simple arcane magic to allocate all strings and the structure itself in a single piece of memory.
When destroying the node, you need only a single call to free(), to the node itself.
struct Node *list = NULL, **nextp = &list;
char buffer[1024];
while (fgets(buffer, sizeof buffer, file) != NULL) {
struct Node *node;
node = malloc(sizeof(struct Node) + strlen(buffer) + 1);
node->key = strtok(strcpy((char*)(node+1), buffer), "/\r\n");
node->value = strtok(NULL, "\r\n");
node->next = NULL;
*nextp = node;
nextp = &node->next;
}
Explanation:
With 20 comments and one unexplained downvote, I think that the code needs some explanation, specially with regards to the tricks employed:
Building a linked list:
struct Node *list = NULL, **nextp = &list;
...
*nextp = node;
nextp = &node->next;
This is a trick to create a linked list iteratively in forward order without having to special-case the head of the list. It uses a pointer-to-pointer to the next node. First the nextp pointer points to the list head pointer; in the first iteration, the list head is set through this pointer-to-pointer and then nextp is moved to the next pointer of that node. Subsequent iterations fill the next pointer of the last node.
Single allocation:
node = malloc(sizeof(struct Node) + strlen(buffer) + 1);
node->key = ... strcpy((char*)(node+1), buffer) ...
We have to deal with three pointers: the node itself, the key string and the value string. This usually would require three separate allocations (malloc, calloc, strdup...), and consequently free separate releases (free). Instead, in this case, the spaces of the tree elements are summed in sizeof(struct Node) + strlen(buffer) + 1 and passed to a single malloc call, which returns a single block of memory. The beginning of this block of memory is assigned to node, the structure itself. The additional memory (strlen(buffer)+1) comes right after the node, and it's address is obtained using pointer arithmetic using node+1. It is used to make a copy of the entire string read from the file ("key/value\n").
Since malloc is called a single time for each node, a single allocation is made. It means that you don't need to call free(node->key) and free(node->value). In fact, it won't work at all. Just a single free(node) will take care of deallocating the structure and both strings in one block.
Line parsing:
node->key = strtok(strcpy((char*)(node+1), buffer), "/\r\n");
node->value = strtok(NULL, "\r\n");
The first call to strtok returns the pointer to the beginning of the buffer itself. It looks for a '/' (additionally for end-of-line markers) and breaks the string there with a NUL character. So the "key/value\n" is broken in "key" and "value\n" with a NUL character in between, and a pointer to the first is returned and stored in node->key. The second call to strtok will work upon the remaining "value\n", strip the end-of-line marker and returning a pointer to "value", which is stored in node->value.
I hope this cleans all questions about the above solution... it is too much for a closed question. The complete test code is here.
You could also use fscanf to parse the input lines directly into keys and values:
char key[80], value[80];
fscanf (pFile, "%s/%s", key, value);
However, the drawback of this approach is that you need to allocate big enough buffers for the keys and values in advance (or use a temp buffer, then copy its value into its final destination, allocated with the right size). With strtok you can check the length of each key and value, then allocate a buffer of exactly the right size to store it.
Update: As commenters pointed out, another (potentially more serious) drawback of fscanf is that it doesn't work for strings containing whitespace.
If you wouldn't mind having aboth the key and the walue in one memory block (two strings), you can just read into a buffer, find the '/' change it into '\0' and point the value pointer just behind the '\0' character. Just don't forget to call free() only on the key value (this will free both the key and the value).
cycle through lines:
1) find '/'
2) devide pair key/value at the position '/'
3) fill key and value
in code:
char* p;
if(p = strchr(str,'/')
{
*p++ = 0;
key = strdup(str);
value = strdup(p);
}

Resources