C strtok not parsing as I want - c

The *id value is initially 0000-0000:c29302. Once it gets send through the split function its value changes to 0000-0000. I think this has to do with it modifying the original value instead of modifying a temporary value. I want the *id value to stay the same. Thanks.
typedef struct node {
char *id;
char *clientid;
char *token;
struct node * next;
} credentials;
void split(credentials * head, char delim[]);
int main()
{
credentials * head = NULL;
head = malloc(sizeof(credentials));
head->id = strdup("0000-0000:c29302");
head->clientid = NULL;
head->token = NULL;
head->next = NULL;
split(head, ":");
print_list(head);
}
void split(credentials * head, char *delim)
{
char *token;
char *temp;
credentials * current = head;
while (current != NULL) {
temp = current->id;
int tempNum = 0;
token = strtok(temp, delim);
current->clientid = token;
while(token != NULL)
{
if(tempNum == 0)
{
current->clientid = token;
} else {
current->token = token;
}
token = strtok(NULL, delim);
tempNum++;
}
current = current->next;
}
}

From man strtok:
If a delimiter byte is found, it is overwritten with a null byte to terminate the current token, [...]
If you do not want your string to be modified you need to either write your own string-tokenizing function or to work with a copy of your string.
Note that if you do continue to use strtok (with a copy of your string), remember that the tokens returned by strtok are not new strings. They are pointers to points within the string you're working with. That means that when you free that string, all the tokens get freed at the same time.

You can use this instead of strtok.
void strsplit(const char* str, const char d, char** into)
{
if(str != NULL && into != NULL)
{
int n = 0;
int c = 0;
for(int i = 0; str[c] != '\0'; i++,c++)
{
into[n][i] = str[c];
if(str[c] == d)
{
into[n][i] = '\0';
i = -1;
++n;
}
}
}
}

Related

What is wrong with my replace string with another string or character using linked list

I have a linked list with many chars which I input from my input (what is the weather today?), to be replaced with another string (for example what replaced with how, so I get how is the weather today?).
But if the given words are right next to each other for example whatwhat, it will change to howwhat, disregarding the second part.
I think the problem is in the compare function, but I have no clue how to fix it, but the logic of replace should go like this:
If the words from my list and the needed word are the same, then proceed to iterate to the position where the next node of the word that should be changed (unwanted word) should be (pretty much the end of the word), then I create a new linked list with character with the wanted word, and connect temp to the start of the list and the next of the list to the position where the next character of the word that needs to be changed (unwanted word), which I found in the first loop.
Also don't roast my input() function, I know it is unsafe I just want to see what unsafe means with my own eyes, while I still have nothing to lose.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int value_c;
struct node *next_c;
struct node *prev_c;
};
typedef struct node string;
int compare(string *head, char *word) {
int counter = 0;
string *temp = head;
for (int i = 0; i < strlen(word); i++) {
if (temp->value_c == word[i]) {
temp = temp->next_c;
counter++;
}
}
if (counter == strlen(word))
return 1;
else
return 0;
}
void print_c(string *head) {
while (head != NULL) {
printf("%c", head->value_c);
head = head->next_c;
}
}
void append_c(string **head, char thing) {
string *newNode = (string *)malloc(sizeof(string));
newNode->value_c = thing;
newNode->next_c = NULL;
if (*head == NULL) {
*head = newNode;
newNode->prev_c = NULL;
return;
}
string *temp = *head;
while (temp->next_c != NULL)
temp = temp->next_c;
temp->next_c = newNode;
newNode->prev_c = temp;
}
string *replace_all1(string *head, char *what, char *with_what) {
string *temp = head;
while (temp != NULL) {
printf("%c ", temp->value_c);
if (compare(temp, what) == 1) {
printf("%i ", 1);
printf("%c ", temp->value_c);
string *new = temp;
for (int i = 0; i < strlen(what) - 1; i++) {
new = new->next_c;
}
string *word = NULL;
for (int i = 0; i < strlen(with_what); i++) {
append_c(&word, with_what[i]);
}
string *word_temp = word;
while (word_temp->next_c != NULL) {
word_temp = word_temp->next_c;
}
word_temp->next_c = new->next_c;
if (temp->prev_c != NULL) {
temp->prev_c->next_c = word;
} else {
head = word;
print_c(head);
temp = word;
print_c(temp);
word->prev_c = NULL;
}
}
temp = temp->next_c;
}
printf("\n");
return head;
}
string *String(char *str) {
string *st = NULL;
int i = 0;
while (str[i] != '\0') {
append_c(&st, str[i]);
i++;
}
return st;
}
string *input() {
char *a = (char *)malloc(sizeof(char));
scanf("%[^\n]", a); //maximum of 1408
string *stri = String(a);
return stri;
free(a);
}
int main() {
string *list = NULL;
string *big_boy_string = input();
//printf("%c", big_boy_string->value_c);
//print_c(big_boy_string);
//printf("\n");
//printf("%i", compare(big_boy_string, "what"));
//printf("%i ", len(big_boy_string));
//printf("\n");
//print_c(slice(big_boy_string, 1, 10));
//print_c(replace(big_boy_string, 'h', 'a'));
//printf("\n");
//print_c(reverse(big_boy_string));
print_c(replace_all1(big_boy_string, "a", "b"));
//getline();
}
char *a = (char*) malloc(sizeof(char));
scanf("%[^\n]",a); //maximum of 1408
The first statement allocates memory for just 1 byte. So the maximum is not 1408, but 1. It can store a single char, or the null-terminator if it's a string, but no more.
Next, scanf() will write to out of bounds memory, and invoke undefined behaviour. The subsequent functions all depend on this undefined behaviour, so I'm not going to look at them.
But then, you've a memory leak in the same function.
return stri;
free(a);
You return before freeing the allocated memory. The call to free() is never executed.
The return value of malloc() is also ignored. Code risks undefined behaviour if the subsequent dereferences are on a NULL pointer.
Aside: The cast is meaningless and may hide a bug. malloc() and family returns a void * that is implicitly converted to the right type.
Re: Also don't roast my input() function, I know its unsafe I just
want to see what unsafe means with my own eyes.
If you are already aware of this, then you shouldn't be asking why your code doesn't work. You are relying on undefined behaviour (playing with fire).
There is no need to look further than the input function: it has undefined behavior or the worst kind because you attempt to read the input string into a very small array, allocated for a single byte. You must fix this first. Since you know the maximum length of your input string, you can use this:
string *input(void) {
char a[1409];
if (scanf("%1408[^\n]", a) != 1) { //maximum of 1408
// invalid or missing input
return NULL;
}
scanf(%*[^\n]"); // consume any remaining characters on the input line
scanf(%*1[\n]"); // consume the newline if present
return String(a);
}
Here is an alternative using getchar() instead of scanf() which is quite tricky and error prone:
string *input(void) {
char a[1409];
int c;
size_t i = 0;
while ((c = getchar()) != EOF && c != '\n') {
if (i + 1 < sizeof(a))
a[i++] = (char)c;
}
if (c == EOF && i == 0) {
/* end of file without any input */
return NULL;
}
a[i] = '\0';
return String(a);
}
The compare function is incorrect: it should return false as soon as the comparison fails and it must test for the end of string (temp == NULL):
int compare(const string *head, const char *word) {
string *temp = head;
for (size_t i = 0; word[i] != '\0'; i++) {
if (temp == NULL || temp->value_c != word[i])
return 0;
temp = temp->next_c;
}
return 1;
}
The replace_all1() function has problems too:
for (int i = 0; i < strlen(what) - 1; i++) will cause undefined behavior if what is an empty string because strlen(what) - 1 is unsigned with the value SIZE_MAX in this case, causing the loop to proceed for a very long time, well beyond the end of the list pointed to by new.
while (word_temp->next_c != NULL) will cause a undefined behavior if the replaced word is empty as word_temp will be NULL.
once you replace the sublist, you do not update temp correctly to point to the node after the replaced one, which you could achieve by setting temp to word_temp.
the function does not free the replaced sublist.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int value_c;
struct node *next_c;
struct node *prev_c;
};
typedef struct node string;
void string_append_char(string **head, int c) {
string *node = malloc(sizeof(*node));
if (node == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
node->value_c = c;
node->next_c = NULL;
if (*head == NULL) {
node->prev_c = NULL;
*head = node;
} else {
string *temp = *head;
while (temp->next_c != NULL)
temp = temp->next_c;
node->prev_c = temp;
temp->next_c = node;
}
}
string *string_new(const char *str) {
string *st = NULL;
for (int i = 0; str[i] != '\0'; i++) {
string_append_char(&st, str[i]);
}
return st;
}
string *string_input(const char *prompt) {
string *st = NULL;
int c;
if (prompt) {
printf("%s", prompt);
}
while ((c = getchar()) != EOF && c != '\n') {
string_append_char(&st, c);
}
return st;
}
void string_print(const char *before, const string *head, const char *after) {
printf("%s", before);
while (head != NULL) {
putchar(head->value_c);
head = head->next_c;
}
printf("%s", after);
}
void string_free(string *head) {
while (head != NULL) {
string *next = head->next_c;
free(head);
head = next;
}
}
int string_compare(const string *head, const char *word) {
const string *temp = head;
for (size_t i = 0; word[i] != '\0'; i++) {
if (temp == NULL || temp->value_c != word[i])
return 0;
temp = temp->next_c;
}
return 1;
}
int string_replace(string **head, const char *what, const char *with_what) {
int count = 0;
if (*what == '\0')
return 0;
string *temp = *head;
while (temp != NULL) {
if (string_compare(temp, what)) {
count++;
// locate the last node of the substring
string *temp_end = temp;
for (size_t i = 0; what[i + 1] != '\0'; i++) {
temp_end = temp_end->next_c;
}
string *next = temp_end->next_c;
if (*with_what == '\0') {
// just delete the substring
if (temp->prev_c != NULL) {
temp->prev_c->next_c = next;
} else {
*head = next;
}
if (next) {
next->prev_c = temp->prev_c;
}
} else {
// create a string from the replacement
string *word = string_new(with_what);
// locate the last node of the new substring
string *word_end = word;
while (word_end->next_c != NULL) {
word_end = word_end->next_c;
}
word->prev_c = temp->prev_c;
if (temp->prev_c != NULL) {
temp->prev_c->next_c = word;
} else {
*head = word;
}
word_end->next_c = next;
if (next) {
next->prev_c = word_end;
}
}
temp_end->next_c = NULL;
string_free(temp);
temp = next;
} else {
temp = temp->next_c;
}
}
return count;
}
int main() {
string *list = string_input("enter string: ");
string_print("input: ", list, "\n");
printf("replacing 'what' to 'how': %d matches\n", string_replace(&list, "what", "how"));
string_print("rep1: ", list, "\n");
printf("replacing 'a' to 'b': %d matches\n", string_replace(&list, "a", "b"));
string_print("rep2: ", list, "\n");
printf("deleting 'h': %d matches\n", string_replace(&list, "h", ""));
string_print("rep3: ", list, "\n");
string_free(list);
return 0;
}
Sample session:
enter string: what is the weather today?
input: what is the weather today?
replacing 'what' to 'how': 1 matches
rep1: how is the weather today?
replacing 'a' to 'b': 2 matches
rep2: how is the webther todby?
deleting 'h': 3 matches
rep3: ow is te webter todby?

C - how to get rid of memory leaks?

How can I get rid of memory leaks from for example this function:
void AddData(Data **head, char *sentence, int number) {
Words *words = NULL;
char delimiters[] = " \n\0";
char *token = strtok(sentence, delimiters);
while (token != NULL) {
if (IsAlphabetical(token) == 1) {
char *string = (char *)malloc((strlen(token) + 1) * sizeof(char));
strcpy(string, token);
AddWords(&words, string);
free(string);
}
token = strtok(NULL, delimiters);
}
Data *temp = *head;
Data *newData = (Data *)malloc(sizeof(Data));
newData->lineNumber = number;
newData->words = words;
newData->pNext = NULL;
if (*head == NULL)
*head = newData;
else {
while (temp->pNext != NULL)
temp = temp->pNext;
temp->pNext = newData;
}
}
My personal opinion is the leaks appear because of newData, temp and words variables.
I have a few similar functions that cause the same problem.
I have also function for deleting Data struct, but when I call it at the end of previous function in such way DeleteData(&temp) program will not execute. I think it's because my whole list is deleted.
void DeleteData(Data **head) {
Data *temp = *head;
while (temp->pNext != NULL) {
Data *next = temp->pNext;
DeleteWords(&temp->words);
free(temp);
temp = next;
}
free(temp); /* to check that */
*head = NULL;
}
How can I fix this?
Here are some problems I identified:
The trailing \0 in char delimiters[] = " \n\0"; is useless.
Testing if (IsAlphabetical(token) == 1) might be too restrictive. In C anything non 0 is true so you might test if (IsAlphabetical(token) != 0) or just if (IsAlphabetical(token)).
Why allocate a copy of the string to pass to AddWords(&words, string); and then free(string) thereafter? If Addwords() does not keep the pointer it gets, there is no need to allocate a copy.
Does AddWords() call strtok()? strtok() is non-reentrant, which means that if AddWords() or any other function called in this loop, such as IsAlphabetical() calls strtok(), the context used in the loop will be corrupted. You should use strtok_r() instead.
in function DeleteData, why do you iterate testing while (temp->pNext != NULL)? The last item in the list does not get freed properly, the DeleteWords(&temp->words); is not called. This may cause a memory leak. You should just write:
void DeleteData(Data **head) {
Data *temp = *head;
while (temp != NULL) {
Data *next = temp->pNext;
DeleteWords(&temp->words);
free(temp);
temp = next;
}
*head = NULL;
}

Add String nodes to an Expression Tree

I've spent many days trying to add strings recursively from a prefix expression like: + 1.5 * 13 2.5 inside a binary tree. I'm using the strtok function to separate elements of the string, but then how can I add the elements to the tree?
My code is very similar to the GeeksForGeeks example: https://www.geeksforgeeks.org/building-expression-tree-from-prefix-expression/, but here they only add characters as data on a node.
typedef struct node {
char * data;
struct node *left, *right;
} node;
// Function to recursively build the expression tree
char* add(node** p, char* a)
{
// If its the end of the expression
if (*a == '\0')
return '\0';
while (1) {
char* q = "null";
if (*p == NULL) {
// Create a node with *a as the data and
// both the children set to null
node* nn = (node*)malloc(sizeof(node));
nn->data = *a;
nn->left = NULL;
nn->right = NULL;
*p = nn;
}
else {
// If the character is an operand
if (*a >= '0' && *a <= '9') {
return a;
}
// Build the left sub-tree
q = add(&(*p)->left, a + 1);
// Build the right sub-tree
q = add(&(*p)->right, q + 1);
return q;
}
}
}
int main()
{
node* s = NULL;
char a[] = "3.5 + 4.7";
// (...) tokens
add(&s, str);
return 0;
}
Thank you very much for your help.
In the example of geeksforgeeks they use char data in the struct. But at your side, you use char * data, so you should use strcpy to copy data from strtok to data of struct. In this case, you have to allocate the memory for thedata of each node. If you do not want to allocate, you can change the char * data in struct node to char data[20].
For example:
node* nn = malloc(sizeof(node));
if(!nn) {
//handle the error
}
nn->data = malloc((sizeof(char)*20) // For example max size of data is equal to 20
char * token = strtok(str, delim); // you choose delim as you want to split the string str
While(token!=NULL) {
strcpy(nn->data, token);
token = strtok(NULL, delim);
}

Read a string and store each string in the array when newline character is found

This program is based on linked list. Read in a string, extract all the substrings separated by newline.
Input should be:
hello world\ngood bye\nWhat a nice day!\n\0
Then, expected output should be:
[hello world]->[good bye]->[What a nice day]->
But, when I run the program and type in:
hello world\ngood bye\nWhat a nice day!\n\0
My output is:
[hello world\ngood bye\nWhat a nice day!\n\0]->
I tried to read NULL character as '\' and 'n' separately, but couldn't handle it. How can I fix it, to print out as expected output?
newTB(char text[]); // function explanation
The function newTB allocates a new textbuffer and initialises its contents with the text given in the array. The lines in the input array are all terminated by a '\n'. The whole text is terminated by a '\0'.
char *dumpTB (TB tb);
The following functions do not alter their textbuffer argument. Allocate and return an array containing the text in the given textbuffer. Each individual line of the textbuffer needs to be terminated by a '\n' (this includes the last line). The whole text must be '\0' terminated. It is the caller's responsibility to free the memory occupied by the returned array. If there are no lines in the textbuffer, return NULL.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct textbuffer *TB;
typedef struct textbuffer {
char *texts;
TB next;
} textbuffer;
char *dumpTB (TB tb) { // my version of dumpTB
TB temp = malloc(sizeof(struct textbuffer));
temp->texts = tb->texts;
temp->next = NULL;
return (temp->texts);
}
TB newTB (char text[]){ // get the array from main function
TB newText = malloc(sizeof(struct textbuffer)); // return the node
newText->texts = text;
//strcpy(newText->texts,text);
newText->next = NULL;
return (newText);
}
void printList(TB tb){ //print entire list
TB curr = tb;
while(curr != NULL){
printf("[%s]-> ",curr->texts);
curr = curr->next;
}
printf("\n");
}
int main(int argc, char * argv[]) {
int i=0;
int j=0;
char str[MAX_TEXT];
char cpy[MAX_TEXT];
char tmp[MAX_TEXT];
TB textList = NULL;
TB list = NULL;
list = textList;
fgets(str, MAX_TEXT, stdin); // input should be like
// hello\nworld\ngood\nbye\n\0
while(str[i] != '\0') {
if(str[i] == '\n') {
cpy[i] = '\0';
strcpy(tmp,cpy);
textList = newTB(tmp);
list = textList;
textList->texts = dumpTB(textList);
//TB newList = malloc(sizeof(struct textbuffer));
//list = textList;
// newList->texts = textList->texts;
textList = textList->next;
j=0;
}
cpy[j++] = str[i++];
}
printList(list);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_TEXT 256
typedef struct textbuffer *TB;
typedef struct textbuffer {
char *texts;
TB next;
} textbuffer;
TB newTB (char text[]){
TB newText = malloc(sizeof(struct textbuffer));
newText->texts = strdup(text);
newText->next = NULL;
return newText;
}
void printList(TB tb){
TB curr = tb;
while(curr != NULL){
printf("[%s]-> ",curr->texts);
curr = curr->next;
}
printf("\n");
}
int main(int argc, char * argv[]) {
int i=0;
int j=0;
char str[MAX_TEXT];
char cpy[MAX_TEXT];
// char tmp[MAX_TEXT];
TB list = NULL;
TB textlist = NULL;
fgets(str, MAX_TEXT, stdin);//E.g. hello\nworld\ngood\nbye\n\0 -> "hello\\nworld\\ngood\\nbye\\n\\0\n"
while(str[i] != '\n' && str[i] != '\0') {
if(str[i] == '\\'){
if(str[i+1] == 'n') {
cpy[j] = '\0';
//strcpy(tmp,cpy);
TB newList = newTB(cpy);
if(textlist == NULL)
textlist = newList;
else {
textlist->next = newList;
textlist = textlist->next;
}
if(list == NULL)
list = newList;
j=0;
i += 2;
} else if(str[i+1] == '0') {
break;
}
}
cpy[j++] = str[i++];
}
printList(list);
//deallocate
return 0;
}
I changed your main function like this:
int main(int argc, char * argv[]) {
int i=0;
int j=0;
char str[MAX_TEXT];
char cpy[MAX_TEXT];
//char tmp[MAX_TEXT];
char* tmp = cpy;
TB textList = NULL;
TB list = NULL;
TB newList = NULL;
//list = textList;
//fgets(str, MAX_TEXT, stdin); // input should be like
// hello\nworld\ngood\nbye\n\0
strcpy(str, "hello\nworld\ngood\nbye\n");
// ... or use a file instead of the line above:
/*
FILE* f = NULL;
*str = '\0';
f = fopen("Sample.txt", "r");
if (!f)
return -1;
(void)fread(str, MAX_TEXT, 1, f);
fclose(f);
*/
while(str[i] != '\0') {
if(str[i] == '\n') {
//cpy[i] = '\0';
//strcpy(tmp,cpy);
//textList = newTB(tmp);
//TB newList = malloc(sizeof(struct textbuffer));
//list = textList;
//newList->texts = textList->texts;
//textList = textList->next;
//j=0;
cpy[j] = '\0';
newList = newTB(tmp);
if (textList) {
textList->next = newList;
textList = newList;
}
else
list = textList = newList;
tmp = &cpy[j+1];
}
else
cpy[j] = str[i];
j++;
i++;
}
cpy[j] = '\0';
printList(list);
// cleanup
for (textList=list;NULL != textList;) {
list = textList;
textList = textList->next;
free(list);
}
return 0;
}
cpy is the copy of the original string with the newline ('\n') characters replaced with end-of-line characters ('\0'), tmp points to the last token in the cpy. list is the head of your list, textList is used as the queue of the list (insertion point for new elements). Furthermore, I replaced fgets with strcpy because you cannot use fgets to get multiple text lines, or you can use a file instead for more text.
I tried to keep your original code as much as possible.

Pointer NULL issues

void addWord(char *word, bucket **bkt, int size)
{
bucket *node, *auxNode;
if(findWord(word, bkt[hash(word, size)]) == 1)
{
return;
}
node = (bucket*) malloc (sizeof(bucket));
node->data = (char*) malloc (strlen(word) * sizeof(char));
memset(node->data, 0, strlen(word));
sprintf(node->data, "%s", word);
if(*bkt == NULL)
{
node->next = NULL;
*bkt = node;
}
else
{
auxNode = (bucket*) malloc (sizeof(bucket));
auxNode = *bkt;
while(auxNode->next != NULL)
{
auxNode = auxNode->next;
}
node->next = NULL;
auxNode->next = node;
}
}
int main(int argc, char **argv)
{
............
bkt = (bucket**) malloc (*sizeHash * sizeof(bucket*));
for(i = 0 ; i < (*sizeHash) ; i++)
{
printf("%d\n", i);
bkt[i] = NULL;
}
.........
if(bkt[hash(pch, *sizeHash)] == NULL)
{
printf("NULL: %s -> %d\n",pch, hash(pch, *sizeHash));
bkt[hash(pch, *sizeHash)] = NULL;
}
addWord(pch, &bkt[hash(pch, *sizeHash)], *sizeHash);
Every time enters in that if, that means that the node send is NULL; But after two inserts, the third although enters in that if, in addWord it arrives not NULL(i put a printf before findWord). I don't understand why this happens. This is a hash table, hash() is djb2 of Dan Bernstein. Could somebody tell my why the NULL pointer isn't send in addWord()?
Surely this:
if(findWord(word, bkt[hash(word, size)]) == 1)
is supposed to be this:
if(findWord(word, *bkt) == 1)
?
Remember that the bkt inside addWord is the &bkt[hash(pch, *sizeHash)] from main: it already points to the hash-entry for word.

Resources