garbage characters while inserting string to a linked list in c - 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';

Related

Segmentation fault with nested strtok possibly?

Here's my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct sentence {
char *words[8];
struct sentence *next;
};
void read_sentence(struct sentence *head, char *words) {
struct sentence *temp, *pointer;
temp = malloc(sizeof *temp);
pointer = head;
int i = 0;
char *delimiter = " ";
char *word = strtok(words, delimiter);
while (word != NULL) {
temp -> words[i++] = word;
word = strtok(NULL, delimiter);
}
while (pointer -> next) {
pointer = pointer -> next;
}
pointer -> next = temp;
}
struct sentence *split_sentences(char *buf) {
struct sentence *head;
head = malloc(sizeof *head);
head -> next = NULL;
char *delimiter = ".";
char *splitted = strtok(buf, delimiter);
while (splitted != NULL) {
read_sentence(head, splitted);
splitted = strtok(NULL, delimiter);
}
return head;
}
int main(int argc, char const *argv[]) {
struct sentence *iter = split_sentences("foo bar. baz qux");
}
What this code essentially does is it parses an input ("foo bar. baz qux") and then it constructs a linked list of sentences using the struct sentence which should have reference to the words within each sentence along with a reference to the next sentence.
Here's the valgrid output:
Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
Command: ./a.out
Process terminating with default action of signal 11 (SIGSEGV)
Bad permissions for mapped region at address 0x400741
at 0x4EDAB9D: strtok_r (strtok_r.c:72)
by 0x400635: split_sentences (in /home/C/a.out)
by 0x4006A0: main (in /home/C/a.out)
It looks like there's an issue with the nested strtok?
strtok() modifies the string. From the manpage:
These functions modify their first argument.
These functions cannot be used on constant strings.
But here
split_sentences("foo bar. baz qux");
you do exactly that. Try the same on a mutable string buffer, for example with
split_sentences(strdup("foo bar. baz qux"));
Furthermore, you might indeed need to use strtok_r(), because you are interleaving strtok()-calls with two different buffers. This will not lead to a segmentation fault, but yields incorrect results.
strtok is not reentrant because it stores some state information in a static char * variable. (Think about it: when the first parameter is NULL, it continues where it left off on the original first parameter, so it needs to store the position where it left off somewhere.)
POSIX.1-2001 and later defines a re-entrant alternative to strtok called strtok_r which stores its state information in storage provided by the caller. strtok_r is not part of the C standard, but should be available on a POSIX.1-2001 compatible system.
Looking at your Valgrind output, it mentions strtok_r, so presumably the C library implementation of strtok is using strtok_r internally on your system. Therefore, you should be able to use it in your program.
void read_sentence(struct sentence *head, char *words) {
struct sentence *temp, *pointer;
temp = malloc(sizeof *temp);
pointer = head;
int i = 0;
char *saveptr;
char *delimiter = " ";
char *word = strtok_r(words, delimiter, &saveptr);
while (word != NULL) {
temp -> words[i++] = word;
word = strtok_r(NULL, delimiter, &saveptr);
}
while (pointer -> next) {
pointer = pointer -> next;
}
pointer -> next = temp;
}
struct sentence *split_sentences(char *buf) {
struct sentence *head;
head = malloc(sizeof *head);
head -> next = NULL;
char *saveptr;
char *delimiter = ".";
char *splitted = strtok_r(buf, delimiter, &saveptr);
while (splitted != NULL) {
read_sentence(head, splitted);
splitted = strtok_r(NULL, delimiter, &saveptr);
}
return head;
}
Both strtok and strtok_r modify the buffer containing the string being split. Therefore, you cannot use them on a string literal because string literals are stored in a non-modifiable, anonymous array of char. Therefore, you need to change your main function to pass a modifiable array of char to split_sentences.
int main(int argc, char const *argv[]) {
char sentences[] = "foo bar. baz qux";
struct sentence *iter = split_sentences(sentences);
}
You cannot nest strtok() calls, as it maintains internal state, used to follow next strings in its first parameter.
If you need to nest strtok() calls in several loop levels, first execute a loop with the first string to get a list of pointers to extracted parts... then iterate that list to use strtok(3) on those strings... get more and more arrays, then iterate all those arrays to further split the input string.

Invalid read of Size 1 when mallocing large String

I have a unique case where I'm trying to store a 4096 character string in a struct member. However, I'm mallocing the usually amount of memory for a shorter string, but am still getting a valgrind error:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct List {
char * name;
int grade;
struct List * next;
};
int main(void) {
struct List * newList;
char * bigString;
int i;
bigString = malloc(sizeof(char)* 4096);
for (i=0; i<4096; i++)
bigString[i] = 'a';
newList = malloc(sizeof(struct List));
newList->next = NULL;
newList->name = malloc(strlen(bigString)+1);
free(bigString);
free(newList->name);
free(newList);
return 0;
}
the line:
newList->name = malloc(strlen(bigString)+1);
Returns an error Invalid read of size 1
But wait a second, I'm mallocing the lenght of the string, plus 1 for the null terminator, what's going on here?
In fact I even tried this:
newList->name = malloc(sizeof(char) * strlen(bigString) +1);
And heck I even tried to null terminate the string after the malloc call:
newList->name[strlen(bigString)] = '\0';
To no avail..
I'm actually beyond confused as to what I've done wrong here. Any ideas?
bigString itself is not null-terminated, so strlen(bigString) results in trying to read past the end of the space allocated for bigString.
You forgot to add a \0 at the end of BigString.

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.

String linked list in C

I am new to linked list in C and the problem I have is that I am trying to make a linked list of Strings, but when I try to print that list it prints first char from two different strings. I think I am messing some pointers. Any help please?
Here is my code...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
typedef struct _song{char *songTitle; char *songAuthor; char *songNote; struct _song *next;}SONG;
int songCount =4;
char SongTitle[songCount];
char AuthorName[songCount];
char SongNotes[songCount];
char songTitle0[21] = "19 problems";
char songArtist0[21]="JayZ";
char songNotes0[81]="JiggaWhoJiggaWhat";
SongTitle[0]=*songTitle0;//points at string songTitle0
AuthorName[0]=*songArtist0;
SongNotes[0]=*songNotes0;
char songTitle1[21] = "Cig Poppa";
char songArtist1[21]="Biggie Smalls";
char songNotes1[81]="I Luv it When you call me big poppa";
SongTitle[1]=*songTitle1;
AuthorName[1]=*songArtist1;
SongNotes[1]=*songNotes1;
SONG *CurrentSong, *header, *tail;
int tempCount=0;
header = NULL;
for(tempCount=0;tempCount<songCount;tempCount++)
{
CurrentSong = malloc(sizeof(struct _song));
CurrentSong->songTitle= &SongTitle[tempCount];
CurrentSong->songAuthor=&AuthorName[tempCount];
CurrentSong->songNote=&SongNotes[tempCount];
if(header == NULL)
{
header=CurrentSong;//head points to first thing in memory
}
else
{
tail->next=CurrentSong;
}
tail = CurrentSong;//always the last thing in the list
tail->next=NULL;//the next pointer is null always
}
tempCount =0;
for(CurrentSong=header; CurrentSong!=NULL; CurrentSong=CurrentSong->next)
{
printf("\n%d: ", tempCount);
printf("Title: %s ",CurrentSong->songTitle);
printf("Author: %s ",CurrentSong->songAuthor);
tempCount++;
}
return 0;
}
That's not how you're supposed to use linked lists.
It's
typedef struct list {
void *data;
struct list *next;
}
SONG *s = (SONG *)songList->data;
Likewise, for cloning strings, you need to use strdup.
E.g.
s->songTitle = strdup(SongTitle);
s->songAuthor = strdup(AuthorName);
s->songNote = strdup(SongNotes);
Don't forget to free the strings once you're done with them.
SongTitle[0]=*songTitle0;//points at string songTitle0
The comment is not true. You're copying the first character songTitle0 into the first position of SongTitle.
Your setup far too complex. You'll want to just assign songTitle0, without any * or &, to the songTitle element of the list's first link; both are of type char*, so that's just a pointer copy. Skip the SongTitle, AuthorName and SongNotes variables, they serve no purpose.
The three variables SongTitle, AuthorName and SongNotes are array of char, not array of string. You need to change their declaration to:
char* SongTitle[songCount];
char* AuthorName[songCount];
char* SongNotes[songCount];
Then, you need to update them like that:
SongTitle[0] = songTitle0;//points at string songTitle0
AuthorName[0] = songArtist0;
SongNotes[0] = songNotes0;
And when you store them in the linked list:
CurrentSong = malloc(sizeof(struct _song));
CurrentSong->songTitle = SongTitle[tempCount];
CurrentSong->songAuthor = AuthorName[tempCount];
CurrentSong->songNote = SongNotes[tempCount];

Beginner C Pointer Problem

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.

Resources