Using the debugger, the linked list seems to be successfully created inside the function, but it doesn't get updated "outside" in main. I don't know why it isn't updating since I'm using addresses and dynamic memory allocation, which if I'm not mistaken, doesn't get "cleared" once the function is exited.
int populate(node* list)
{
node* temp = NULL;
while(1)
{
printf("insert word: ");
char* word = getstring();
if(strcmp(word, "stop") == 0)
{
break;
}
//create a node
node* n = malloc(sizeof(node));
if(n == NULL)
{
return 1;
}
//put stuff in node
n->word = word;
n->next = NULL;
if (list == NULL) //first case only
{
list = n;
temp = n;
}
else
{
//set previous next to current node
temp->next = n;
//set pointer to current node
temp = temp->next;
}
}
}
int main()
{
node* list = NULL;
while(1)
{
printf("insert command: ");
char* word = getstring();
if (strcmp(word, "stop") == 0)
{
break;
}
else if (strcmp(word, "add") == 0)
{
populate(list);
}
else if (strcmp(word, "read") == 0)
{
readList(list);
}
}
}
Also, after my code runs, is the memory I've allocated automatically freed? Or am I gobbling up small chunks of my computers memory every time I test my program. (I'm using Xcode)
You need to pass the pointer node* list as a double pointer (pointer to pointer) instead of a pointer:
int populate(node** list)
{
This is because C language has value semantics. Everything is passed by value. So when you pass the list to populate(), you create a copy of the original pointer. They are both pointing to the same memory, but changes to one of the pointer will not be reflected in the other. This is why your list never gets updated.
Everything else will remain mostly the same. When calling the populate function you need to pass the address of the list:
populate(&list);
And in the populate() function, every occurrence of list will become *list since you need to de-reference it to get the original pointer.
Related
I am trying to create a function to delete a certain node if its value matches the value entered by the user. I created a case if there is only a single node, but after deleting the node with free(curr_node) and calling traverse function, the cmd prints out numbers endlessly. What am I missing?
typedef struct Node {
int data;
struct Node *next;
}Node;
Node *head = NULL;
int node_number = 0;
void traverse(Node *head, int count) {
int i = 1;
if(head == NULL) {
printf("No nodes to traverse!");
return;
}
printf("%d node(s), with their respective value: \n", count);
while(head != NULL) {
if(i == count)
printf("%d\n", head->data);
else
printf("%d-", head->data);
head = head->next;
i++;
}
}
void delete_item(Node *head) {
Node *curr_node = head;
int value;
printf("Enter value to search by: ");
scanf("%d", &value);
while(curr_node != NULL) {
if(curr_node->data == value) {
if(curr_node->next == NULL) {
free(curr_node);
head = NULL;
printf("Node deleted successfully!\n");
return;
}
}
//curr_node = curr_node->next;
}
}
Node *create_item() {
Node *result = NULL;
result = (Node *)malloc(sizeof(Node));
if(result == NULL) {
printf("Couldn't allocate memory!");
return 0;
}
printf("Value of node %d: ", node_number + 1);
scanf("%d", &result->data);
result->next = NULL;
node_number++;
return result;
}
int main() {
int nodes;
Node *temp;
head = create_item();
delete_item(head);
traverse(head, node_number);
return 0;
The change to head is not captured by the caller. The fact is, head is actually a local variable to delete_node, and any changes to it (not to be confused with changed through it using deference operations), are not being captured by the caller.
All function arguments in C are by-value. Some will say "that's not true for arrays"; they're wrong. Used in an expression, the "value" of an array is defined by the language standard as a temporary pointer referring to the address of the first element. I.e. still by-value, its just the value isn't what you may expect. But in your case, head is by value. If you had a function void foo(int x) you already know that modifying x within foo does not change the caller's int they passed; the same is true here. Just because its a pointer makes no difference. If you want to modify a caller-argument you have to build the road to get there.
There are two general schools around this.
Use a pointer to pointer argument and pass the address of head in main. This requires deference of the pointer-to-pointer to get the actual list head, but also allows you to modify the callers pointer.
Use the return result of the function to communicate the current list head back to the caller (i.e. the head after whatever operation is being performed.
The first is more complicated, but allows you to use the return result for other purposes (like error checking, hint). The latter is easier to implement. Both will accomplish what you want. The former is shown below:
void delete_item(Node **head)
{
int value;
printf("Enter value to search by: ");
if (scanf("%d", &value) == 1)
{
while (*head)
{
if ((*head)->data == value)
{
void *tmp = *head;
*head = (*head)->next;
free(tmp);
printf("Node deleted successfully!\n");
break;
}
head = &(*head)->next;
}
}
}
The caller, main in this case, needs to be modified as well:
delete_item(&head); // <== note passed by address now.
#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 trying to get inputs from the user and then append the struct to the end of the linked list. This works fine but I want to add another feature that would prevent the input being added if all the details are exactly the same. (In this case email, class, first and last name)
The for loop I added in the middle is what I tried to do to achieve this feature. The program goes into the loop without any problems but the input will still be added. How would I fix this?
struct request *append(struct request *list){
char f_name[NAME_LEN+1];
char l_name[NAME_LEN+1];
char e_address[EMAIL_LEN+1];
char c_name[CLASS_LEN+1];
//get input
printf("\nEnter email: ");
scanf("%s", e_address);
printf("\nEnter class: ");
scanf("%s", c_name);
printf("\nEnter child first name: ");
scanf("%s", f_name);
printf("\nEnter child last name: ");
scanf("%s", l_name);
//allocate memory for the structure
struct request* p = (struct request*) malloc(sizeof(struct request));
struct request *temp = list;
//////////WHAT I TRIED BUT DIDN'T WORK
for (p = list, temp = NULL; p != NULL; temp = p, p = p -> next) {
if (strcmp(p -> first, f_name) == 0 && strcmp(p -> last, l_name) == 0 && strcmp(p -> email, e_address) == 0 && strcmp(p -> class, c_name) == 0) {
printf("Output: request already exists");
return list;
}
}
//store the data
strcpy(p->first, f_name);
strcpy(p->last, l_name);
strcpy(p->email, e_address);
strcpy(p->class, c_name);
p->next = NULL;
//if list is empty return pointer to the newly created linked list
if (list == NULL) {
return p;
}
//traverse to the end of the list and append the new list to the original list
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = p;
return list;
}
First off, with those scanf's you should do something like this to avoid buffer overflows.
As to your question, you should malloc p after your for-loop since we should only allocate it if there is no other node with the exact same info (And as paddy said, in your code it causes a memory leak because you set p to point to something else hence losing that newly malloc-ed data).
Your loop is more complex than it needs to be. Admittedly I can't see why the for-loop wouldn't detect a copy, maybe providing some input cases would help clear it up? Either way I'd replace that section of the code with this:
// Get a pointer to the head of the list
struct request *temp = list;
// Find and node with the exact same data
while(temp->next != NULL) {
if(!strcmp(temp->first, f_name) && !strcmp(temp->last, l_name) && !strcmp(temp->email, e_address) && !strcmp(temp->class, c_name)){
printf("Output: request already exists");
return list;
}
temp = temp->next;
}
// Allocate p and reset temp
struct request *p = (struct request*) malloc(sizeof(struct request));
temp = list;
// etc
I have a linked list of "words" that I'm trying to build, I made a function called "add_to_mem" which adds to the linked list the next word.
I've made a couple of checks on the code, and found out that he works twice - once when the linked list is a NULL, and once when it's not - and it is does working, but in the third time I'm calling to the method - I'm getting an "A heap has been corrupted" error.
The code:
typedef struct { unsigned int val : 14; } word;
typedef struct machine_m
{
word * current;
int line_in_memo;
char * sign_name;
struct machine_m * next_line;
}Machine_Memo;
The function:
/*Adding a word to the memory.*/
void add_to_mem(word * wrd, int line, char * sign_name)
{
Machine_Memo * temp = NULL, *next = NULL;
if (machine_code == NULL)
{
machine_code = (Machine_Memo *)malloc(sizeof(Machine_Memo));
if (machine_code == NULL)
{
printf("Memory allocation has failed.");
exit(1);
}
machine_code->current = wrd;
machine_code->line_in_memo = line;
machine_code->sign_name = sign_name;
machine_code->next_line = NULL;
}
else
{
printf("token has been reached");
temp = machine_code;
next = (Machine_Memo *)malloc(sizeof(Machine_Memo)); //Line of error
if (next == NULL)
{
printf("MEMORY ALLOCATION HAS FAILED. EXITING PROGRAM.\nThe problem has occured on code line %d", 775);
exit(0);
}
next->current = wrd;
next->line_in_memo = line;
next->sign_name = sign_name;
next->next_line = NULL;
while (temp->next_line != NULL)
{
temp = temp->next_line;
temp->next_line = next;
}
}
}
As far as I understand the code, it does not create a linked list. it creates nodes, but does not link them together.
at first call, the machine_code (head of list) is created.
at next call, the node 'next' is created, however, the loop:
while (temp->next_line != NULL)
{
temp = temp->next_line;
temp->next_line = next;
}
does nothing as the 'machine_code->next' value is null. so code inside the loop is not executed. and we do not get here a linked list, but sporadic nodes not connected each to other.
you may wanted (as pointed at the other post here) to have something like:
while (temp->next_line != NULL)
{
temp = temp->next_line;
}
temp->next_line = next;
Here
while (temp->next_line != NULL)
{
temp = temp->next_line;
temp->next_line = next; // move out of the loop
}
you may want to move the last assignment outside of the loop.
so I'm trying to write a method that deletes a node and all nodes attached to it, but I'm confused on what to do. I know the free method releases the memory used, and when I created the node, I used malloc. I'm unsure why free isn't removing the node and what should I do instead.
struct node {
char *data;
struct node *left;
struct node *right;
}*child = NULL;
void delete(node* root){
char array[13];
node *toDelete;
//takes in name of node to be deleted
//scan method to find the node to delete and deletes all of the children of the node first before deleting
printf ("Please specify a name to delete\n");
scanf("%s", array);
toDelete = scan(root, array); //return which node to delete
removeChild(&toDelete); //helper method here to go through and delete each children
if(toDelete == NULL) {
printf("ERROR -- Node does not exist");
}
}
void removeChild(node **trash){
if((*trash)->left == NULL && (*trash)->right == NULL) { //no parents
free(trash);
*trash = NULL;
}
else if((*trash)->left == NULL && (*trash)->right != NULL) { //have mother
removeChild((*trash)->right);
}
else if((*trash)->left != NULL && (*trash)->right == NULL) { //have father
removeChild((*trash)->left);
} else{ //have both
removeChild((*trash)->left);
removeChild((*trash)->right);
}
}
I didn't look thoroughly at your code, but I saw this which doesn't do what you think it does:
void removeChild(node * trash){
if(trash->left == NULL && trash->right == NULL) { //no parents
free(trash);
trash = NULL;
}
...
The last statement which intends to clear the pointer only does that for the parameter. The caller's pointer (which is passed to removeChild()) does not have its pointer NULLed. That is because parameters passed to a function are copied. They are not passed by reference.
Presumably other code could depend on the pointer being cleared, and so this would not satisfy it.