Realloc struct array as a function parameter yields segmentation fault? - c

I have searched quite a bit, before asking, but I can't seem to make this function work.
I have this array of structs with 2 strings (char*)
and the function put() that adds a new struct, Unless the key already exists in that case it just ovewrites the current value with the new one.
Despite I am passing the array by reference and not making a local copy in the function, the memory still is corrupted (Segmentation Fault).
The source code is compiled under Ubuntu 15.10 on latest version of gcc.
Thanks in advance for your help guys!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 3
struct store{
char *key;
char *value;
};
void put(char *key, char *value, struct store **store, int size){
int i, found;
struct store *temp = realloc(*store, (size + 1) * sizeof(struct store));
for(i = 0; i < size; ++i){
if(strcmp(key, store[i]->key) == 0){ //Key found, overwrite new value.
store[i]->value = strdup(value); //Assume that every value is null terminated
found = 1;
break;
}
}
if(found) return;
*store = temp;
if(!store){
perror("realloc failed");
exit(EXIT_FAILURE);
}
store[size]->key = strdup(key); //New element
store[size]->value = strdup(value);
return;
}
int main(){
int i = 0;
struct store *store = malloc(N * sizeof(struct store));
if(!store){
perror("malloc failed");
exit(EXIT_FAILURE);
}
store[0].key = strdup("123a");
store[1].key = strdup("456b");
store[2].key = strdup("789c");
store[0].value = strdup("John");
store[1].value = strdup("Sam");
store[2].value = strdup("Mary");
for(i = 0; i < N; ++i)
printf("%s, %s\n\n",store[i].key,store[i].value); //This works fine
put("123a","Jim",&store,N);
for(i = 0; i < N; ++i)
printf("%s, %s\n\n",store[i].key,store[i].value);
put("653a","Tom",&store,N);
for(i = 0; i < N+1; ++i)
printf("%s, %s\n\n",store[i].key,store[i].value);
return 0;
}

struct store *temp = realloc(*store, (size + 1) * sizeof(struct store));
for(i = 0; i < size; ++i){
if(strcmp(key, store[i]->key) == 0){ //Key found, overwrite new value.
store[i]->value = strdup(value); //Assume that every value is null terminated
found = 1;
break;
}
}
if(found) return;
*store = temp;
If the key is found, you don't assign temp to *store. realloc can move the allocated memory to a completely new address, thus leaving *store a dangling pointer. And you really should also check that temp isn't null as well.
There's also the problem of your misuse of store. store is the the address of the pointer you passed into the function, not the first element of an array.
You need to index the array like this (*store)[i].

Related

Finding size of array of structs C

I am trying to find the size of the struct array that I am using to do a sort on it. Not sure how to implement it with the sizeof() function that is normally used in nonstruct arrays.
I am also trying to figure what I am doing wrong when initializing the vehicle struct in the arguments vs the temp struct variable.
error: incompatible types when initializing type ‘struct data *’ using type ‘struct data’
struct data *temp = vehicles[j];
This is the data struct that I am using
struct data{
char *model;
float engineSize;
int cost;
char *color;
};
This is the code that I am currently running for the sort that I am using
void bubbleSortFloats(struct data vehicles[], int check)
{
int i, j, n;
n = sizeof(vehicles)/sizeof(vehicles[0]);
// If check == 1 then ascending sort
if(check == 1){
for (i = 0; i < n-1; i++){
// Last i elements are already in place
for (j = 0; j < n-i-1; j++){
if (vehicles[j].engineSize > vehicles[j+1].engineSize){
struct data temp = vehicles[j];
vehicles[j] = vehicles[j+1];
vehicles[j+1] = temp;
}
}
}
}
// If check == 0 then decending sort
if(check == 0){
for (i = 0; i < n-1; i++){
// Last i elements are already in place
for (j = 0; j < n-i-1; j++){
if (vehicles[j].engineSize < vehicles[j+1].engineSize){
struct data temp = vehicles[j+1];
vehicles[j+1] = vehicles[j];
vehicles[j] = temp;
}
}
}
}
}
This is the update with the readfile function that I am using
struct values * readFile(){
FILE *fp;
int c;
int count = 0;
char *line = NULL;
size_t len = 0;
fp = fopen("hw3.data", "r");
while ((c = fgetc(fp)) != EOF){
if(c == '\n'){
count++;
}
}
if (feof(fp)){
rewind(fp);
struct data *vehicles = malloc((sizeof(struct data))* count);
count = 0;
char *token = NULL;
while (getline(&line, &len, fp)!= -1){
printf("%s", line);
token = strtok(line, " ");
vehicles[count].model = malloc(strlen(token) + 1);
strcpy(vehicles[count].model, token);
token = strtok(NULL, " ");
vehicles[count].engineSize = atof(token);
token = strtok(NULL, " ");
vehicles[count].cost = atoi(token);
token = strtok(NULL, " ");
vehicles[count].color = malloc(strlen(token) + 1);
strcpy(vehicles[count].color, token);
free(line);
line = NULL;
len = 0;
}
struct values *value = malloc(sizeof(struct values));
value.vehicles = vehicles;
value.count = count;
return value;
}
This code
sizeof(vehicles)/sizeof(vehicles[0]);
will only work with true arrays.
In
void bubbleSortFloats(struct data vehicles[], int check);
vehicles look like an array but in fact it is a pointer, this function
definition is the same as
void bubbleSortFloats(struct data *vehicles, int check);
In C you cannot pass true arrays to the functions, they always are passed as
pointers. Even with code like this:
void foo(int arr[10])
{
printf("%lu\n", sizeof arr / sizeof *arr);
}
int main()
{
int arr[10] = { 0 };
foo(arr);
}
I get a warning of my compiler:
a.c: In function ‘foo’:
a.c:6:25: warning: ‘sizeof’ on array function parameter ‘arr’ will return size of ‘int *’ [-Wsizeof-array-argument]
printf("%lu\n", sizeof arr);
^~~
a.c:4:14: note: declared here
void foo(int arr[10])
^~~
and if I execute it, I get 2, because on my system the size of a pointer is 8
and the size of an int is 2. That's why the sizeof arr / sizeof *arr doesn't
work in a function that gets an array passed.
You have to calculate the length of the array before you call
bubbleSortFloats and pass that length to the function. The correct function
would be:
void bubbleSortFloats(struct data *vehicles, size_t len, int check)
{
...
}
We don't see how you created the array, but the function that creates it will
know the size:
void foo(void)
{
struct data vehicles[SOME_LEN];
...
bubbleSortFloats(vehicles, sizeof vehicles / sizeof *vehicles, check);
}
or if you did it with malloc
void foo(void)
{
size_t len = ...;
struct data *vehicles = malloc(len * sizeof *vehicles);
if(vehicles == NULL)
return;
...
bubbleSortFloats(vehicles, len, check);
}
edit
Jeffrey Hennen asked in the comment section:
I made it clear. I am going to want to return a structure and an int count for the size of the array of structures
Like I said in the comments, if you want to return more than one value, you have
essentially two options:
Declare a struct that encapsulates all the returning values and return it
Or pass pointers to the function and let the function update the values
provided by the pointers.
You've chosen way 1, so I guess you have this struct:
struct values {
struct data *vehicles;
size_t count;
};
Then the way you are returning it, is OK. Of course you should check that the
last malloc did not return NULL (you are ignoring that throughout the whole
function, though).
The second option would be:
The easiest way would be:
struct data *readFile(size_t *length) {
if(length == NULL)
return NULL;
...
while (getline(&line, &len, fp)!= -1){
...
};
// NOT NEEDED ANYMORE
//struct values *value = malloc(sizeof(struct values));
//value.vehicles = vehicles;
//value.count = count;
*length = count; // UPDATE the length through the pointer
return vehicles; // return the array
}
and the calling function would do:
void foo(void)
{
size_t count;
struct data *vehicles = readFile(&count);
if(vehicles == NULL)
{
// error
return;
}
do_something_with_the_vehicles(vehicles, count);
free_the_vehicles(vehicles, count);
}
Of course you would have to write a function free_the_vehicles (you can of
course choose another name) that frees all the memory allocated.
struct data *temp = &vehicles[j];
Otherwise it is incompatible as you try to assign the pointer with the structure. You need to assign the address of the structure
When copying a struct, a direct assignment does not work.
Suggest using the function: memcpy().
memcpy( temp, &vehicles[j], sizeof( struct data );
similar considerations exist for all the statements that are trying to copy the 'struct data' instances

Struct pointer array segmentation fault

I'm building an autocomplete program that takes a few characters of input and gives back suggested words to complete the characters. I have an AutoComplete_AddWord function that adds words for suggestion. However, whenever I try to access my structs completions array(holds up to 10 suggested words for given host table's letters) a segmentation fault is thrown. Not sure where I'm going wrong. Thanks for any help.
struct table {
struct table *nextLevel[26];
char *completions[10]; /* 10 word completions */
int lastIndex;
};
static struct table Root = { {NULL}, {NULL}, 0 }; //global representing the root table containing all subsequent tables
void AutoComplete_AddWord(const char *word){
int i; //iterator
char *w = (char*)malloc(100*(sizeof(char));
for(i = 0; w[i]; i++){ // make lowercase version of word
w[i] = tolower(word[i]);
}
char a = 'a';
if(w[0] < 97 || w[0] > 122)
w++;
int index = w[0] - a; // assume word is all lower case
if(Root.nextLevel[index] == NULL){
Root.nextLevel[index] = (struct table*) malloc(sizeof(struct table));
TotalMemory += sizeof(table);
*Root.nextLevel[index] = (struct table){{NULL},{NULL},0};
}
else
// otherwise, table is already allocated
struct table *pointer = Root.nextLevel[index];
pointer->completions[0] = strdup(word); //Here is where seg fault keeps happening
}
OK, so there are a lot of errors with this, and you obviously didn't test it and compile it. But I was curious so I took a closer look, and the problem stems from here:
for(i = 0; w[i]; i++){ // make lowercase version of word
w[i] = tolower(word[i]);
}
You are diving right into a loop checking w[0], a fresh, uninitialized block of memory.
Changing it to this:
for(i = 0; word[i]; i++){ // make lowercase version of word
w[i] = tolower(word[i]);
}
Will solve that problem. Fixing the other miscellaneous problems mentioned above, a non-segfaulting version of the code looks like this:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
struct table {
struct table *nextLevel[26];
char *completions[10]; /* 10 word completions */
int lastIndex;
};
int TotalMemory = 0;
static struct table Root = { {NULL}, {NULL}, 0 }; //global representing the root table containing all subsequent tables
void AutoComplete_AddWord(const char *word){
int i; //iterator
char *w = (char*)malloc(100*(sizeof(char)));
for(i = 0; word[i]; i++){ // make lowercase version of word
w[i] = tolower(word[i]);
}
char a = 'a';
if(w[0] < 97 || w[0] > 122) w++;
int index = w[0] - a; // assume word is all lower case
if(Root.nextLevel[index] == NULL){
Root.nextLevel[index] = (struct table*) malloc(sizeof(struct table));
TotalMemory += sizeof(struct table);
*Root.nextLevel[index] = (struct table){{NULL},{NULL},0};
}
struct table *pointer = Root.nextLevel[index];
pointer->completions[0] = strdup(word); //Here is where seg fault keeps happening
}
int main(int argc, char **argv)
{
AutoComplete_AddWord("testing");
return 0;
}
I can't speak for what happens next with this program, but at least this gets you past the segfault.

storing value to doubly linked list in C

I have a doubly linked list data structure which is well formulated, as I have tested it on different inputs.
But, here is a piece of code where I have problem. I am trying to read in a line of string from a file, and store the values by converting them into integers in an array of integer called num. The code is fine unto here as I have printed the entries out and checked them. But when I try storing them into my doubly linked list, I get all the values correct except the second value which is an arbitrary long integer. I have my code and output below:
num_read is a function which reads all the values in a doubly linked list, and takes the array num and its length as arguments.
#include "DlistInterface.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Dnode *num_read(int *,int *);
int main(){
Dnode *number;
int num[100];
char a[10];
char *lineptr = NULL;
int j = 0;
int i = 0;
int index = 0;
size_t len;
ssize_t read;
FILE *fp;
fp = fopen("Dlist_v_array.txt","r");
while ((read = getdelim(&lineptr,&len,32,fp)) != -1){
i = 0;
index = 0;
while (1){
if ((lineptr[i] == ' ') || (lineptr[i] == '\n')) break;
else a[index++] = lineptr[i++];
}
a[index] = '\0';
num[j] = atoi(a);
printf("%d ",num[j]);
j++;
}
//printf("\n %d",j);
printf("\n");
fclose(fp);
free(lineptr);
number = num_read(num, &j);
while (number != NULL){
printf("%d ",number->data);
number = number->next;
}
printf("\n");
return 0;
}
Dnode *num_read(int *n, int *len){
int k;
for (k=1; k< *len;k++){
//printf("%d ",n[k]);
}
printf("\n");
Dnode *number = (Dnode *)malloc(sizeof(Dnode *));
number->data = n[0];
number->next = NULL;
number->prev = NULL;
Dnode *another_node;
Dnode *temp;
another_node = number;
k = 1;
while(k < *len){
temp = (Dnode *)malloc(sizeof(Dnode));
temp->data = n[k++];
temp->next = NULL;
another_node->next = temp;
temp->prev = another_node;
another_node = temp;
}
return number;
}
I get this as the output:
12 21 33 4 5 6 7 8 9
12 -2109715456 33 4 5 6 7 8 9
The first line of output is because the verification of values read in the number array, which is correct according to the values in the .txt file.
But the same values on the next line have their corresponding second entries to be a weird number, which happens to be their always, no matter what I do.
I desperately need help on this one. I will be very thankful to you all for the help. Please help!!!
Incorrect amount of memory assigned #BLUEPIXY.
// Dnode *number = (Dnode *)malloc(sizeof(Dnode *));
Dnode *number = (Dnode *)malloc(sizeof(Dnode));
To avoid this mistake in the future, and to create simpler original and maintainable code, use;
// pointer = malloc(sizeof *pointer * number_elements)
Dnode *number = malloc(sizeof *number); // number_elements == 1 in OP's case
// check pointer
if (number == NULL) return NULL; // detect and handle out-of-memory somehow
This has advantages
In C, the cast on malloc() is not needed.
by using the sizeof *pointer rather than sizeof(element_type), less chance to get the wrong type, as OP did in this post, and less to update should the type change.
By using the sizeof() first, the memory needs are calculated in at least size_t math. This becomes important with large programs: Consider int h,w; malloc(sizeof *pointer*h*w) vs. malloc(h*w*sizeof *pointer) where h*w overflowed int math, but not size_t math.
Always check for out-of-memory. At a minimum, it saves time in debugging as at least you know, proper memory allocated. Note: on some systems, if number_elements is 0 (and so is sizeof *pointer * number_elements) allocating 0 bytes may return NULL and that is not an out of memory condition.
pointer = malloc(sizeof *pointer * number_elements)
if (pointer == NULL && number_elements > 0) Handle_OOM();

malloc(): memory corruption in a weird place

I've been dealing with an annoying memory corruption error for a couple of hours. I've checked every related thread here, and I couldn't fix it.
First of all, I'm writing a simple Terminal in C. I'm parsing the commands between pipe (|) and redirection (>, <, etc.) symbols and place them in the queue. Nothing complicated!
Here's the data structure for the queue;
struct command_node {
int index;
char *next_symbol;
struct command_node *nextCommand;
int count;
char **args;
};
When I'm storing small strings in the **args pointer, everything works just fine. However, when one of the arguments is long, I get malloc(): memory corruption error. For example, the following 1st command works fine, the 2nd command causes the error
1st: ls -laF some_folder | wc -l
2nd: ls -laF /home/enesanbar/Application | wc -l
I run the debugger, it showed that the malloc() call for the new node in the queue causes the error.
newPtr = malloc( sizeof(CommandNode) );
I'm carefully allocating the array of strings and freeing after I'm done with them as follows:
char **temp = NULL;
temp = malloc(sizeof(char*) * number_of_args);
/* loop through the argument array */
for (i = 0; i < number_of_args; i++) {
/* ignore the remaining commands after ampersand */
if (strcmp(args[i], "&") == 0) return;
/* split commands by the redirection or pipe symbol */
if (!isSymbol(args[i])) {
temp[count] = malloc(sizeof(strlen(args[i])) + 1);
strcpy(temp[count], args[i]);
count++;
/* if it is the last argument, assign NULL to the symbol in the data structure */
if (i + 1 == number_of_args) {
insertIntoCommands(&headCommand, &tailCommand, temp, NULL, count);
for (j = 0; j < count; j++) free(temp[j]);
count = 0; // reset the counter
}
}
else {
insertIntoCommands(&headCommand, &tailCommand, temp, args[i], count);
for (j = 0; j < count; j++) free(temp[j]);
count = 0; // reset the counter
}
}
I must have missed something, or there's something I don't know about the **args fields and the allocation of the new node although it's nothing I haven't done before.
but how could wrapping a number around the sizeof cause an error in the allocation of a node? I'm just trying to understand out of curiosity.
Like I was saying in my comment, you try to get the size of the pointer inside the strlen function and not the lenght which is provided through the function.
Please take a look at the following:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(void){
char *name = "Michi";
size_t length1, length2;
length1 = strlen(name);
length2 = sizeof strlen(name);
printf("Length1 = %zu\n",length1);
printf("Length2 = %zu\n",length2);
return 0;
}
Output:
Length1 = 5
Length2 = 8
One more thing, after you free(temp[j]) don't forget to free(temp) also.
Something like this:
#include <stdio.h>
#include <stdlib.h>
int main(void){
long unsigned int size = 2,i;
char **array;
array = malloc(sizeof(char*) * size * size);
if (array == NULL){
printf("Error, Fix it!\n");
exit(2);
}
for (i = 0; i < size; i++){
array[i] = malloc(sizeof(char*) * 100);
}
/* do code here */
for (i = 0; i < size; i++){
free(array[i]);
}
free(array);
return 0;
}

invalid pointer from trying to use realloc for an array of structs in c

My program compiles but I am not working with pointers and realloc correctly. I have tried looking at other examples but I can't seem to translate it to my own program. The point of the program is to read in words from a file and increment the count if they appear more than once. Once the array of structs goes over my base (5), I want to realloc space, copy the array over and then add the next word.
Any help would be greatly appreciated!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BASE 5
#define MAX 50
typedef char *string;
struct wordCount
{
string word;
unsigned int count;
};
int main (void)
{
unsigned int i;
unsigned int incremented;
unsigned int j;
char temp [40];
struct wordCount wordArray[BASE];
struct wordCount *holder;
FILE *infile;
j = 0;
infile = fopen("input.txt","r");
while (fscanf(infile, "%s", temp) == 1) {
incremented = 0;
for (i = 0; i < j; i++){
if(strcmp(temp,wordArray[i].word) == 0){
wordArray[i].count++;
incremented++;
}
}
if (incremented == 0){
if (j<BASE){
wordArray[j].word = (char *)malloc((strlen(temp)+1) *
sizeof(char));
strcpy(wordArray[j].word,temp);
wordArray[j].count = 1;
j++;
} else {
holder = realloc(wordArray, sizeof(wordArray) +1);
*wordArray = *holder;
wordArray[j].word = (char *)malloc((strlen(temp)+1) * sizeof(char));
strcpy(wordArray[j].word,temp);
wordArray[j].count = 1;
j++;
}
}
}
fclose(infile);
/* bring in next file*/
/*delete du plicates */
/*sort*/
for (i = 0; i < j; i++) {
printf("%s ", wordArray[i].word);
printf("%d\n", wordArray[i].count);
}
/* and when done:*/
for(i = 0; i < j; i++){
free(wordArray[i].word);
}
return 0;
}
Here's the most obvious place you're going wrong:
holder = realloc(wordArray, sizeof(wordArray) +1);
Note this line from the man page of realloc():
void *realloc(void *ptr, size_t size);
...
Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc().
Your wordArray is a statically allocated array, it was not dynamically allocated via malloc() or friends.

Resources