Beginner C Pointer Problem - c

I am a new C user have problems with pointers.
The function add_word(*word_to_add) should take a c string and add it to the appropriate word_node linked list. However, subsequent additions seem to be overwriting the word element of all nodes in the hash table. I think this is happening because I am setting each nodes word element to be a pointer to word_to_add rather than copying the value of word_to_add.
#define HASH_TABLE_SIZE 10
static char **word_list;
struct word_node {
char* word;
struct word_node *next;
};
static struct word_node *word_hash_table[HASH_TABLE_SIZE];
static int hash(char *word) {
int ascii_char;
int key;
key = 0;
while (*word != '\0') {
ascii_char = tolower(*word);
key += ascii_char;
word++;
}
key %= HASH_TABLE_SIZE;
return key;
}
void ws_add_word(char *word_to_add)
{
int word_position;
word_position = hash(word_to_add);
if (word_hash_table[word_position] == NULL)
{
struct word_node* p;
p = malloc(sizeof(struct word_node));;
p->word = word_to_add;
p->next = NULL;
word_hash_table[word_position] = p;
++num_words;
} else {
struct word_node* p;
p = word_hash_table[word_position];
while (p->next != NULL)
{
p = p->next;
}
struct word_node* q;
q = malloc(sizeof(struct word_node));
q->word = word_to_add;
q->next = NULL;
p->next = q;
++num_words;
}

I think your code is ok as is. If you are having problems, it may be in how you are calling the function. For example, here is a quick & dirty sample:
#include <stdio.h>
#include <stdlib.h>
int num_words;
/* paste sample code here */
#define HASH_TABLE_SIZE 10
// rest of code
void ws_add_word(char *word_to_add)
{
// function code
}
/* end of sample code */
int main (void)
{
char a[] = "Hello";
char b[] = "Helkp"; // chosen to have the same hash result
ws_add_word((char *)&a);
ws_add_word((char *)&b);
}
I compiled with gcc -g and ran through gdb. Doing so and stepping through ws_add_word and examining the contents of word_hash_table seems to do what you want. If it still doesn't work, you should give an example of how you are calling ws_add_word.
Also, if you simply change p->word = word_to_add with strcpy(p->word,word_to_add), you will probably get a seg fault because p->word has not been set to anything meaningful yet. You need to p->word = (char *)malloc(N) where N is big enough, and then strcpy, if that's what you really want to do. Whether you want to or not depends on whether the memory location pointed to by char *word_to_add will be valid the next time you need to use it.

You cannot just equate two strings or character pointers like:
char* p1, p2;
p1=p2; // THIS IS INVALID
In your code you have done this mistake two times:--
p->word = word_to_add;
and
q->word = word_to_add;
This says that you are making p->word point to word_to_add which is a pointer.It will just start referring to the same object but not copy the string which you expect.
It won't copy the contents of word_to_add to q->word, which you are assuming to be done.
You need to copy the strings using any string copy function like: strcpy, strncpy or memcpy.
replace p->word = word_to_add with
strcpy(p->word,word_to_add);
and similarly
replace q->word = word_to_add with
strcpy(q->word,word_to_add);
--
Kr. Alok

Looks good to me, except for line 10 in ws_add_word.
Change
q->word = word_to_add;
to
p->word = word_to_add;

The node's char pointer 'word' seems to point to the original string rather than holding a copy of its own. This is fine as long as the original string doesn't change. For example:
//Assume word_to_add is "String 1"
p->word = word_to_add;
//Now change word_to_add to "String 2"
//After this p->word would be "String 2"
I don't know if that was the intended behavior. You might want to allocate memory for every 'word' pointer in the node structure and copy the word_to_add string.

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.

Deallocationg char** inside a struct

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

C memory allocation for linked list

I'm trying to make an Linked List that essentially holds a string (rather than a character array). I keep getting segmentation fault (core dumped) and I'm not sure where/how I'm allocating memory wrong
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct mystring
{
char letter;
int size;
int isHead;
struct mystring*next;
};
struct mystring * create_empty_string(int size)
{
struct mystring * string = malloc(sizeof(struct mystring));
string->size = size;
string->isHead = 0;
return string
}
struct mystring * make_string(struct mystring * list,char * string)
{
for(int i = 0 ; i < strlen(string) ; i++)
{
list->letter= string[i];
list = list->next;
}
return list;
}
void printList(struct mystring* list) {
//start from the beginning
while(list->letter != '\0') {
printf("(%c) ",list->letter);
list = list->next;
}
}
int main()
{
struct mystring * string = create_empty_string(10);
string = make_string(string, "hey");
printList(string);
}
When letter is defined as char letter; and your compiler allows you to do string->letter = malloc(sizeof(char)); without complaining, this means that you are trying to compile without the slightest bit of warnings enabled. You are not going to go very far like that. Figure out how to enable all warnings on your compiler, then perhaps work on the warnings a bit to disable the really annoying ones, and from that moment on your compiler will be helping you to avoid doing such nonsensical things as assigning the result of malloc() to a char.
As noted, your create_empty_string() function is poorly constructed. I suggest building the linked list one node at a time by feeding individual characters into a function called append_to_string() or similar, which will create a new node and link it to the previously constructed list (or become the list itself if it's the first node).

garbage characters while inserting string to a linked list in c

So, what Im trying to achieve with this, is to create a linked list with three strings as data. The output shows the expected strings, but adds some garbage symbols, f.ex.: expected "string pierwszy", got : "string pierwszyn~rŚÝ".
I also tried to print out the strlen(tmp->word) and I got 3. I dont get it, i thought it would be 1. I dont get, why is it like this.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct element element;
struct element{
char * word;
element * next;
};
element * head = NULL;
void addWord(char * new_word){
printf("new_word: %s\n\n\n", new_word);
element *tmp = NULL;
tmp = malloc(sizeof(element));
element *current = head;
tmp->word = malloc(sizeof(char) * strlen(new_word)+1);
strncpy(tmp->word, new_word, strlen(new_word));
tmp->word[strlen(new_word)] = "\0";
tmp->next = current;
head = tmp;
}
void free_list(element * node){
if(node != NULL){
free_list(node->next);
free(node->word);
free(node);
}
}
void print_list(element * node){
element * tmp = node;
while(tmp != NULL){
printf("word: %s\n", tmp->word);
tmp = tmp->next;
}
}
int main()
{
char * name1 = "string pierwszy";
char * name2 = "drugi";
char * name3 = "333trzeci";
addWord(name1);
addWord(name2);
addWord(name3);
print_list(head);
free_list(head);
return 0;
}
The problem is the following line:
tmp->word[strlen(new_word)] = "\0";
There is a difference between "\0" and '\0'. '\0' is correct in this situation, since it's simply a null character. "\0" is a string containing a null character, so it's exactly the same thing as
{'\0', '\0'} (one null character for the one you entered and one which is added automatically).
Since arrays in C are treated as pointers for some purposes, the code that you wrote creates an array of two null characters in the memory, takes the address of the first element, converts it to a char using the ASCII table and stores it in the string. So what you did is basically equivalent to doing this:
char someString[2];
someString[0] = '\0';
someString[1] = '\0';
tmp->word[strlen(new_word)] = (char)&(someString[0]);
Since the string doesn't have any terminated null character because of this, it doesn't know where the string ends so it continues a couple of characters giving you the characters that just happened to be in the memory.
So the first "garbage" character as you say is the ASCII equivalent of the address of some string, and the other ones are what happened to be in the memory right there and right then.
The correct code is of course the following:
tmp->word[strlen(new_word)] = '\0';

What is causing this segfault?

I get a segfault after calling mygets(). Here is my code:
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct _charlist{
char ch;
struct _charlist *next;
}charlist;
static struct termios old, new;
void mygets(char** p);
char getche(void);
char getch_(int echo);
void resetTermios(void);
void initTermios(int echo);
int main(void){
char *p;
printf("\nWho loves orange soda?: ");
mygets(&p);
printf("'%s' loves orange soda!", p);
}
void mygets(char** p){
char c;
charlist *root, *curr;
unsigned i, count=0;
root=NULL;
while((c = getche()) != '\n'){
count++;
if(!root){
root = (charlist*) malloc(sizeof(charlist));
root->ch = c;
root->next = NULL;
curr = root;
}
else{
curr
->next = (charlist*) malloc(sizeof(charlist));
curr->next->ch = c;
curr->next->next = NULL;
curr = curr->next;
}
}
//now request string space.
*p = (char*) malloc((count+1)*sizeof(char));
printf("\np is now malloced"); //This line doesn't get printed!
//move linked list into string space.
curr = root;
for(i=0; i<=count; i++){
*p[i] = curr->ch;
curr = curr->next;
}
//null-terminate the string.
*p[i] = '\0';
}
Can someone tell me why I get a segfault?
I can't post this question unless the ratio of code to question is lower than some arbitrary threshold. Therefore, there now follows the first paragraph of Alice in Wonderland, for your consideration.
Alice was beginning to get very tired of sitting by her sister on the
bank, and of having nothing to do: once or twice she had peeped into
the book her sister was reading, but it had no pictures or
conversations in it, 'and what is the use of a book,' thought Alice
'without pictures or conversation?'
When func is called, it is passed a copy of the local variable p in main. This copy is then assigned the malloced area in func. The original p in the main is never modified, so its contents remain undefined, causing a segmentation fault when printf dereferences p in order to print the string.
You may want func to return a char* pointing to the newly malloc'd area.
You pass the argument to the function by value. So according to the function declaration
void func(char* p);
parameter p is a local variable of the function that will be destroyed after exiting the function. Any changes of the local variable do not influence on the argument.
You could define the function the following ways
char * func(){
unsigned count = 10;
char *p = (char*) malloc(sizeof(char)*(count+1));
//p is given a string after this, but problem is the above line.
return p;
}
and call it as
p = funct();
or
void func(char ** p){
unsigned count = 10;
*p = (char*) malloc(sizeof(char)*(count+1));
//p is given a string after this, but problem is the above line.
}
and call it as
func( &p );
The problem is with:
*p[i] = curr->ch;
Should be:
(*p)[i] = curr->ch;
You want to access the i'th character of where p is pointing to. Not dereference the ith pointer in an array of pointers.
Same problem with *p[i] = '\0'; later.
Also you did not malloc enough space, as your loop writes count + 1 characters and then you write an extra null terminator, so you should either malloc count + 2 or adjust your loop to finish at i<count, not i<=count. (probably the latter).
Also, it'd be useful to check curr != NULL before dereferencing it, so that if you do have an off-by-one error then you don't get undefined behaviour.

Resources