I am quite new to coding and got stuck with a problem. I tried to solve it myself and have been googling a lot, but I still do not have a solution to this. Maybe one of you can help?
This is my code:
int main(int argc, char **argv) {
struct node {
char *str;
int count;
struct node *next;
};
struct node head = { argv[1], 1, NULL };
for (int i = 2; i < (argc); i++) {
for (struct node *p = &head; (p != NULL); p = p->next) {
printf("%s,%s\n", argv[i], p->str);
if (strcmp(argv[i], p->str) == 0) {
printf("case1\n");
p->count++;
break;
}
else if ((strcmp(argv[i], p->str) != 0) && p->next) {
printf("case2\n");
printf("Adresse, auf die p zeigt: %p", &p);
continue;
}
else if ((strcmp(argv[i], p->str) != 0) && (!p->next)) {
printf("case3\n");
struct node *oldhead = &head;
head.str = argv[i];
head.count = 1;
head.next = oldhead;
break;
}
}
}
// Print how many times each string appears
return 0;
}
The goal is to create a linked list that contains all the arguments I gave to the main() when calling the program. If there is a duplicate, the structure should count them. For example, if i call the program like ./a.out foo fool foo the result should be a list of length two, where the first element contains the string "foo" and count 2, and the second element contains the string "fool" and has a count of 1. The problem is the else if-statement within the inner for loop. This is the only part where the inner for loop should actually be used and assign p->next to p. Unfortunately that is not happening. The result is that the inner for loop starts over and over again and the pointer p points to the same address all the time (I used printf to figure that out).
Does any of you have an idea what could be the problem here? I tried everything I could and tried to find a solution online ...
Thanks a lot!!!
The issue is in this part of the code
else if ((strcmp(argv[i], p->str) != 0) && (!p->next)) {
printf("case3\n");
struct node *oldhead = &head;
head.str = argv[i];
head.count = 1;
head.next = oldhead;
break;
}
You need to allocate a new struct and then put its address in the last struct entry.
else if ((strcmp(argv[i], p->str) != 0) && (!p->next)) {
printf("case3\n");
struct node *oldhead = p;
p = (struct node *) malloc(sizeof(node));
if (p == NULL) { .... manage the error ... }
oldhead->next = p;
p->str = argv[i];
p->count = 1;
p->next = NULL;
break;
}
Now you're creating nodes and stringing them together. You were effectively updating the same node before.
struct node *oldhead = &head;
head.str = argv[i];
head.count = 1;
head.next = oldhead;
That's not creating a new node. It's just creating a new reference to the same node, therefore causing an infinite loop when you try to read the linked list until the end. Therefore, your program only ever has one node. You need to actually allocate and create new ones.
The main problem here is
struct node *oldhead = &head;
which you should do malloc:
struct node *oldhead = (struct node*) malloc(sizeof(struct node));
so you really allocate a piece of memory for your new node. And because you have malloc, you should do free at the end of your program as well:
while(...) {
free(deepest_node)
}
the way you do the loop above is to go from the farthest node in the linked list all the way back to the head.
The other issue is that, you should not append your new node to head:
head.next = oldhead;
but should be to p, which is the last node in your linked list:
p -> next = oldhead;
Related
This is just a snippet of the code, but I checked and know for a fact that all the strings save nicely into the "new" element (in function SortedInsert), but then the "new" doesn't link to the head?
I've tried everything I could think, hopefully I'm just missing something obvious.
typedef struct _Info* Position;
typedef struct _Info{
char name[MAX];
char surname[MAX];
Position next;
} Info;
(declaration inside main function:
Info headInfo = {.name = {0}, .surname {0}, .next = NULL};
Position head = &headInfo;
)
int SortedInsert(Position head, char name[], char surname[]){
Position prev = NULL, temp = NULL, new = NULL;
prev = head;
temp = head->next;
new = (Position)malloc(sizeof(Info));
if(!new){
return EXIT_FAILURE;
}
strcpy(new->name, name);
strcpy(new->surname, surname);
new->next = NULL;
if(head->next==NULL){
temp = new;
}
else{
// first sort, by surname
while(strcmp(temp->surname, new->surname) < 0){
prev = temp;
temp = temp->next;
}
// second sort, by name
while(strcmp(temp->name, new->name) < 0){
prev = temp;
temp = temp->next;
}
new->next = prev->next;
prev->next = new;
}
return EXIT_SUCCESS;
}
int PrintList(Position head){
Position temp = NULL;
temp = head->next;
while(temp){
printf("%s ", temp->name);
printf("%s\n", temp->surname);
printf("---\n");
temp = temp->next;
}
return EXIT_SUCCESS;
}
Some issues:
temp = new does not insert anything into the list. It merely copies a reference to the new node into a local variable. The assignment should be to head->next. Moreover, there is no need to create a separate case for this. It can be handled with the code you have in the else part.
The retrieval of the insert point is not correct. If in the first loop the strcmp call returns 1 (not 0), then the second while loop should not iterate at all: it doesn't matter in that case what the first name is like. The last name of temp is already greater, so the insertion point has been found. Similarly, if the strcmp call returns 0, the second loop should keep verifying that the last name is still the same in its second iteration,...etc. Moreover, this logic can be combined in one loop.
Not a problem for the correct execution, but still:
Many consider it bad practice to typedef a pointer to a struct where you dereference the pointer regularly in your code. See the answers to Is it a good idea to typedef pointers? for some background. So I'd keep using Info *.
Create a separate function for creating and initialising a node.
The comments that say "first sort", "second sort" are misleading. There is no sorting happening in the loop that follows the comment. The list is already sorted. The process that follows just intends to find the insertion spot according to the sort order. So the comment could be improved.
Many consider it better not to cast the value returned by malloc.
Here is the correction of the SortedInsert function, together with the separated function for node creation:
Info *createNode(char name[], char surname[]) {
Info *new = malloc(sizeof(*new));
if (new != NULL) {
strcpy(new->name, name);
strcpy(new->surname, surname);
new->next = NULL;
}
return new;
}
int SortedInsert(Info *head, char name[], char surname[]){
Info *new = createNode(name, surname);
if (new == NULL) {
return EXIT_FAILURE;
}
Info *prev = head;
Info *temp = head->next;
// Find insertion spot according to sort order
while (temp != NULL) {
int cmp = strcmp(temp->surname, new->surname);
if (cmp == 0) { // It's a tie. Then use name as discriminator
cmp = strcmp(temp->name, new->name);
}
if (cmp >= 0) { // Found insertion spot
break;
}
prev = temp;
temp = temp->next;
}
new->next = prev->next;
prev->next = new;
return EXIT_SUCCESS;
}
I am trying to insert words into a hash table and it looks like it works but when I try to print the word inside the node (just to check if its still correct) I get a bogus value. When my code prompts for the word I said 'Hey' and when it prompts for place I said '5'. The string that is printed out(which is supposed to be the word inside the node) is HH9[]A\A]A^A_f. What is happening to the word inside the node and am I inserting the node correctly?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct node
{
char word[20];
struct node *next;
}
node;
int main (void)
{
node* table[10];
char wrd[10];
printf("Word to insert: ");
fgets(wrd, 10, stdin);
int place;
printf("Place to insert word: ");
scanf("%d", &place);
node *n = malloc(sizeof(node));
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
if(table[place] == NULL)
{
n = table[place];
n->next = NULL;
}
else
{
n->next = table[place];
n = table[place];
}
printf("Word inside node: %s \n" , n->word);
}
EDIT
I changed the code and tried to implement it on a larger scale but my while loop gives me a segfault. This is the function I put it in:
FILE* dct = fopen ("/dictionaries/large", "r");
char *wrd = NULL;
while(fscanf(dct, "%s", wrd) != EOF)
{
int place = hash(wrd);
node *n = malloc(sizeof(node));
node *anchor = NULL;
node *end = NULL;
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
n->next = NULL;
if (!end) //Initial state
anchor = end = n;
else //Every following node.
end = end->next = n;
strcpy(n->word, wrd);
n->next = table[place];
table[place] = n;
counter++;
}
return false;
It has to read from the dictionary file and load the word into memory(or a hash table).
A linked list is a linked list because it does not have a fixed size.
The table array is therefor superfluous.
What you need for your linked list to work is to remember the anchor and nothing more.
A small example:
Node *anchor = NULL;
Node *end = NULL;
Node *node = malloc(sizeof(Node));
node->next = NULL;
if (!end) //Initial state
anchor = end = node;
else //Every following node.
end = end->next = node;
At this point, you can still access the node you've just filled. Don't forget to iterate over your list later and free those allocations though.
This code doesn't make any sense:
if(table[place] == NULL)
{
n = table[place]; // since we know table[place] is null, that sets n to null!
n->next = NULL; // We just set n to NULL, we can't access n->next!
}
else
{
n->next = table[place]; // This sets n to a garbage value since table[place] was never assigned a value
n = table[place]; // This leaks the value we malloc'ed. We were supposed to link it to the list!
}
#include <stdio.h>
#include <stdlib.h>
struct node {
char *str;
struct node *next;
};
struct node *start = NULL;
struct node *temp = NULL;
struct node *q = NULL;
void sonaEkle(char *veri) {
struct node *eklenecek = (struct node *)malloc(sizeof(struct node));
eklenecek->str = veri;
eklenecek->next = NULL;
if (start == NULL) {
start = eklenecek;
} else {
q = start;
while (q->next != NULL) {
q = q->next;
}
}
}
void yazdir() {
q = start;
while (q->next != NULL) {
printf("%s", q->str);
q = q->next;
}
printf("%s", q->str);
}
int main() {
char *veri;
while (1 == 1) {
printf("enter string");
scanf("%s", veri);
sonaEkle(veri);
yazdir();
}
return 0;
}
I have created a Linked list.
This linked list adds the string it received from the user to the end. But my code is giving a loop error. How can I fix this?
for example: user input:abc bcd cde
output:abc => bcd => cde
This is an infinite loop
while(1 == 1) {
printf("enter string");
scanf("%s",veri);
sonaEkle(veri);
yazdir();
}
Rewrite it in this way
while( puts("enter string") && scanf("%s",veri) == 1 ) {
sonaEkle(veri);
yazdir();
}
And also you need to allocate memory for veri before you can use it in scanf. But you could as well just making it an array.
char veri[SIZE];
There are multiple problems with the code
char *veri;
while(1 == 1){
First statement veri needs memory, since it is a pointer, you need some thing like this veri = malloc(somesize);
Second statement is an infinite loop, you need some termination point, better use something like below to break the infinite loop.
while(1){
// after malloc
scanf("%s",veri);
//enter exit whenever you want to exit from program.
if(strcmp(veri,"exit") == 0)
break;
Function sonaEkle you are allocating memory for struct node* , but you are not returning updated nodes address start
you need to have sonaEkle like this struct node* sonaEkle(char *veri) and return start after every update and no need to cast malloc.
4)
else {
q=start;
while(q->next != NULL) {
q=q->next;
}
The above part just iterates list, you need to add new nodes to q->next when it reaches to NULL and return start afterwards in order to have next elements in the list.
Correct all those problems , to make you program work.
NOTE:
check the pointers for NULL after every malloc
free the malloc'ed memory once you are done with your program.
I am attempting to delete several occurrences of a word stored in a linked list. However, these words are stored by character in a single node instead of as a whole word in a list. For example, The pink flamingo is stored as:
T->h->e-> ->p->i->n->k-> ->f->l->a->m->i->n->g->o. Say the user wants to find pink. They have to loop through and delete each of these nodes.
I have attempted to create a loop which copies the contents of the linked list into a search function. I think copy this search function into another string. I am able to successfully delete the first occurrence of the desired character. However, I'm unable to do much else. I've attempted several times to push the node to the next node after deletion, but that also hasn't worked. It produced the same error.
void nodeDeletions(struct node** reference_to_headNode, struct node* deleteNode){
if(*reference_to_headNode == NULL){
return;
}
if(*reference_to_headNode == deleteNode){
printf("Test A\n");
*reference_to_headNode = deleteNode->nextNode;
}
if(deleteNode->nextNode != NULL){
printf("Test B\n");
deleteNode->nextNode->previousNode = deleteNode->previousNode;
}
if(deleteNode->previousNode != NULL){
printf("Test C\n");
deleteNode->previousNode->nextNode = deleteNode ->nextNode;
}
free(deleteNode);
}
void deleteWord(struct node** reference_to_headNode, char word_to_delete[]){
struct node *tempNode;
struct node *nextNode;
int searchIndex = 0;
int characterIndex = 0;
const int arraySize = 101;
const int arraySize2 = 202;
char searchWordIndex[arraySize];
char searchWordCopyIndex[arraySize2];
if(*reference_to_headNode == NULL){
return;
}
else {
for (tempNode = *reference_to_headNode; tempNode != NULL; tempNode = tempNode->nextNode) {
searchWordIndex[searchIndex] = tempNode->character;
searchIndex++;
}
strcpy_s(searchWordCopyIndex, searchWordIndex);
int length_of_searchIndex = strlen(searchWordCopyIndex);
int length_of_deletionWord = strlen(word_to_delete);
tempNode = *reference_to_headNode;
for (searchIndex = 0; searchIndex < length_of_searchIndex; searchIndex++) {
printf("Test 1\n");
if(tempNode != NULL) {
if(tempNode->character == word_to_delete[0]) {
for (characterIndex = 0; characterIndex < length_of_deletionWord; characterIndex++) {
printf("Test 2\n");
if (searchWordCopyIndex[searchIndex] == word_to_delete[characterIndex]) {
printf("Test 3\n");
if (tempNode->character == word_to_delete[characterIndex]) {
printf("Test 4\n");
printf("%c\n", tempNode->character);
printf("%c\n%c\n", word_to_delete[characterIndex], searchWordCopyIndex[searchIndex]);
nextNode = tempNode->nextNode;
nodeDeletions(reference_to_headNode, tempNode);
tempNode = nextNode;
}
else {
printf("Test 5\n");
tempNode = tempNode->nextNode;
}
}
}
}
}
tempNode = tempNode->nextNode;
}
}
}
Phew! That's a lot of indented clode blocks. And a lot of auxiliary arrays and indices. And very long variable names. :)
Basically, you are dealing with three different types of iterating forwards through stuff, which are all present in your code:
Traverse a character string:
while (*s) {
// do stuff with *s
s++;
}
Traverse a linked list:
while (p) {
// do stuff with *p
p = p->next;
}
Traverse a linked list via a reference to the source, so that you can modify it:
while (*p) {
// do stuff with **p
p = &(*p)->next;;
}
You only have to combine these three basic loops.
You can walk through the list with the third method (because you need to be able to update the head or next links when you delete). For each node you visit, compare the "tail" of that node with an auxiliary pointer p and the string s using the other two methods simultaneously. When the string matches, *s == '\0' and p points to the first node after the word. Delete all nodes by advancing the head until the head is p.
In other words:
Traverse the list via *head.
At each node:
set p = *head and s to the begining of the string;
traverse the list and the word while the letters match;
If *s == '\0', there is a match. Now, *head points to the start of the word to delete in the list, p points to the first node after the word in the list, which may be NULL.
If there is a match, advance *head until *head == p, deleting the nodes as you go.
Or, in code:
void delete_word(struct node **head, const char *str)
{
while (*head) {
struct node *p = *head;
const char *s = str;
while (p && *s && p->c == *s) {
p = p->next;
s++;
}
if (*s == '\0') {
while (*head != p) {
struct node *del = *head;
*head = (*head)->next;
delete_node(del);
}
} else {
head = &(*head)->next;
}
}
}
So I'm pretty new to C, but not to programming. I am trying to learn C and so I decided to try implementing a simple linked list.
Here is the code:
#include <stdio.h>
typedef struct node node;
struct node {
char *word;
node *next;
};
// Returns a node.
node node_new(char *word) {
node n;
n.word = word;
n.next = NULL;
return n;
}
// Traverses the linked list, spitting out the
// words onto the console.
void traverse(node *head) {
node *cur = head;
while (cur != NULL) {
printf("I have %s.\n", cur->word);
cur = cur->next;
}
printf("Done.\n");
return;
}
// In here I get circular references whenever I pass a second argument.
void dynamic(int argc, char **argv) {
printf("DYNAMIC:\n");
node n = node_new("ROOT");
node *cur = &n;
int i;
for (i = 0; i < argc; i++) {
node next = node_new(argv[i]);
cur->next = &next;
cur = &next;
}
traverse(&n);
}
void predefined(void) {
printf("PREDEFINED:\n");
node n = node_new("ROOT");
node a = node_new("A");
node b = node_new("B");
node c = node_new("C");
n.next = &a;
a.next = &b;
b.next = &c;
traverse(&n);
}
int main(int argc, char **argv) {
predefined();
dynamic(argc, argv);
return 0;
}
If I just run it without arguments ("./test") the output is:
PREDEFINED:
I have ROOT.
I have A.
I have B.
I have C.
Done.
DYNAMIC:
I have ROOT.
I have ./test.
Done.
but if I put any arguments on, instead of "I have ./test." it gives an infinite loop of whatever the last argument on the command line was ("./test one two three" gives "i have three." over and over ignores the "one" and "two", but the preceding lines are the same).
I think it has to do with bad pointer management in the dynamic function, but I can't figure out why it's setting itself to its own "next" node.
The problem is here:
for (i = 0; i < argc; i++) {
node next = node_new(argv[i]);
cur->next = &next;
cur = &next;
}
By allocating next like this, it remains tied to the stack and doesn't actually change address on each iteration. It should be a new object each time:
for (i = 0; i < argc; i++) {
node *next = malloc (sizeof node);
next->word = argv[i];
next->next = NULL;
cur->next = next;
cur = next;
}
Also, node_new() can't be used because it doesn't allocate any lasting new memory either.
The problem is in your for loop. Every iteration uses the same memory location on the stack to store the next variable. So, effectively, the memory location given by &next is a constant for your entire for loop, and by the time you run traverse, that memory location contains last value of next.
Your for loop is equivalent to this version, which might shed more light:
int i;
node next; // note this line
for (i = 0; i < argc; i++) {
next = node_new(argv[i]);
cur->next = &next;
cur = &next;
}
You'll need to create new nodes on the heap, if you want to be able to pass their addresses around, or store their addresses in other data structures. Read up on malloc and free.