Struct pointer array segmentation fault - c

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.

Related

Why am I getting a segmentation fault when I try to assign an element from an array to a same type value in my data structure in C?

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.

Realloc struct array as a function parameter yields segmentation fault?

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].

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;
}

printf overwriting seeminlgy unrelated data?

EDIT: I should add how I have this all set up. The struct definition and prototypes are in mystring.h. The function definitions are in mystring.c. The main is in mystringtest.c. For mystring.c and mystringtest.c, I have #include "mystring.h" at the top. I'm compiling like gcc -o test.exe mystring.c mystringtest.c. Not sure if any of that matters, but I'm new with C so I'm just trying to include everything.
I have a good deal of experience with Java but am pretty new to C. I imagine this is related to pointers and memory but I'm totally at a loss here for what's going on. Here's my code:
typedef struct {
char *chars;
int length;
int maxSize;
} String;
int main() {
char *a;
a = readline();
String *s = newString(a);
int b = length(s);
printf("length is %d \n", b);
}
I run the program and enter "hello" (as prompted by readline()). I've stepped through the program and after length(s), s->chars is still a pointer to the array of chars 'hello'. After the print statement, s->chars becomes a pointer to the array of chars 'Length is %d \n'. I'm totally at a loss for what I'm doing wrong. I'm working on a virtual machine if that matters at all. Any help is greatly appreciated. I'll give the code for newString and length too.
int length(String *s) {
char *temp = s->chars;
char b = *temp;
int count;
if (b == '\0') { count = 0; }
else { count = 1; }
while (b != '\0') {
b = *(temp+count);
count++;
}
return count;
}
String *newString(char *s) {
String st;
st.length = 20;
st.maxSize = MAXCHAR;
char *temp = malloc(20 * sizeof(char));
char b = *s;
int count = 0;
while (b != '\0') {
*(temp + count) = b;
count++;
b = *(s+count);
if (count == st.maxSize) { break; }
if (count == st.length) {
st.length = st.length + 20;
temp = realloc(temp, st.length * sizeof(char));
}
}
st.chars = temp;
return &st;
}
String *newString(char *s) {
String st;
...
return &st;
}
You are returning a pointer to a local variable. After newString returns, the local variable no longer exists, so you have a dangling pointer.
Either allocate st with malloc, or return it by value.
you must null terminate the string after the while loop, you have not left space for the null terminator. Also I don't see why you need to realloc
//using strlen will eliminate the need for realloc, +1 is for the null terminator
int len = strlen(s)
char *temp = malloc((len * sizeof(char)) +1);
//null terminate
*(temp+count) = '\0';
st.chars = temp;

Writing a sorting function to sort an array of pointers, pointing to structures

I'm writing a function to sort an array of pointers, pointing to structures, based on the value of a zip code. I found a sort function online (it's my first time writing a sort function) and thought I would play around with it and see what happens and I keep getting the error "Array type 'char[7] is not assignable' and I'm not sure why. Any ideas?
Thank you.
struct personCatalog {
char name[50];
char address[50];
char cityState[50];
char zipCode[7];
} ;
#include <stdio.h>
#include "header.h"
#include <stdlib.h>
#include <string.h>
void bubble_sort(struct personCatalog *arrayOfPointers[]){
int num1 = 0;
while (arrayOfPointers[num1] != NULL) {
atoi(arrayOfPointers[num1++]->zipCode);
}
int progress = 0;
do {
int i;
progress = 0;
for (i = 0; i < num1 - 2; ++i) {
if (arrayOfPointers[i]->zipCode > arrayOfPointers[i + 1]->zipCode) {
struct personCatalog temp = *arrayOfPointers[i];
arrayOfPointers[i] = arrayOfPointers[i + 1];
arrayOfPointers[i + 1] = &temp;
progress = 1;
}
}
} while (progress);
}
The C language doesn't inherently know how to assign 7 chars to 7 other chars. It only allows you to assign one primitive type to another at a time:
zipCode[0] = temp[0]
zipCode[1] = temp[1];
// etc.
To copy arrays in C which are contiguous, like zipCode, you can use memcpy:
memcpy(zipCode, temp, 7);
Also, it's possible that I misread your intent on my tiny screen, but you also shouldn't assign a struct pointer to zipCode either.
There are a couple problems with this code, but you're getting this error because you're trying to assign values to arrays in the highlighted lines; that's why it's complaining about assignment to array type char[7]. This doesn't make much sense, since you can't change the location of an array. You can either swap the bytes with a call to memcpy, or, perhaps more idiomatically, change the definition of struct personCatalog such that zipcode is a true char * rather than a char array.
The array consists of pointers. So the temp thing you are using to swap them should also be a pointer.
for (i = 0; i < num1 - 1; ++i) {
if ( strcmp( arrayOfPointers[i]->zipCode
, arrayOfPointers[i + 1]->zipCode
) > 1) {
struct personCatalog *temp ;
temp = arrayOfPointers[i];
arrayOfPointers[i] = arrayOfPointers[i + 1];
arrayOfPointers[i + 1] = temp;
progress = 1;
}
}
Also, the loop condition i < num1-2 was wrong. Should be num1 -1, IMO.
Update: it appears zipcode is a textstring, so I replaced ">" by "strcmp()"

Resources