Keeping struct variable in storage in loop? - c

I have the following code.
#include <stdio.h>
#include <string.h>
struct node
{
char value[30];
struct node *next;
};
int main()
{
struct node *current = NULL;
struct node *head = NULL;
while (1)
{
char input[30];
scanf("%29s", &input);
if (strcmp(input, "exit") == 0) break;
struct node new;
strcpy(new.value, input);
if (head == NULL)
{
head = &new;
}
else
{
current->next = &new;
}
current = &new;
}
return 0;
}
This is supposed to store multiple inputs of String in a linked list. After a long time I found the problem in this code. The problem is that after each loop the struct variable (list node) is destroyed in storage, and if I initialize a new struct variable it is placed at the same place in the RAM where I had the previous list node. So the only list node that remains is the last one I create. How can I make it so that the list nodes don't get destroyed after each loop run?
Above, I use list node and struct variable interchangeably, because in my program the struct variable represents a list node that is supposed to be created.

Well, you can do it in linear code, but it's easier if you break down the code flow into whatever job each step has to do. Let's start:
We leave the "intro" unchanged, except for adding stdlib:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char value[30];
node *next;
};
Now we "shorthand" the declaration (yes, yes, macros are evil, but sometimes, they are useful)
// typedefs are a good alternative here if you dislike macros
#define node_t struct node
Let's start with a helper: adding nodes
node_t* CreateNewNode (node_t* prev)
{
// (type*)malloc(sizeof(type)) is explicit and useful
// but not mandatory in C; you might need it if you write C++
// that shares C code though
// details here: https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc
node_t* node = (node_t*)malloc(sizeof(node_t));
node->next = NULL;
if (prev != NULL)
prev->next = node;
return node;
}
What we're basically doing here is allocating memory for new nodes and because it's a linked list, we're keeping the chain going referencing the previous node.
Now let's add some clean-up. We destroy the linked list. (well, we have to, we allocated memory so now we have to deallocate it)
void DestroyNodes (node_t* head)
{
node_t* current = head;
while (current != NULL)
{
free(current);
current = current->next;
}
}
We c-p the entry-point and the first part of it (replacing the struct with the macro)
int main (void)
{
node_t* current = NULL;
node_t* head = NULL;
while (1)
{
char input[30];
scanf("%29s", &input);
if (strcmp(input, "exit") == 0)
break;
While new is C++ keyword, and we're playing in C and we showed the compiler that the code has nothing to do with objects, I would really not tempt the compiler gods here, so don't use that as a variable name "just in case".
Now we start using our helpers, along with some different names for the vars:
node_t* prev = current;
current = CreateNewNode(prev);
strcpy(&(current->value)[0], input); // strcpy(current->value, input); is fine too
if (head == NULL)
head = current;
}
Then the deallocation before returning from main() to avoid memory leaks:
DestroyNodes(head);
So, summarizing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char value[30];
node *next;
};
// typedefs are a good alternative here if you dislike macros
#define node_t struct node
node_t* CreateNewNode (node_t* prev)
{
// (type*)malloc(sizeof(type)) is explicit and useful
// but not mandatory in C; you might need it if you write C++
// that shares C code though
// details here: https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc
node_t* node = (node_t*)malloc(sizeof(node_t));
node-> next = NULL;
if (prev != NULL)
prev->next = node;
return node;
}
void DestroyNodes (node_t* head)
{
node_t* current = head;
while (current != NULL)
{
current = current->next;
free(current);
}
}
int main (void)
{
node_t* current = NULL;
node_t* head = NULL;
while (1)
{
char input[30];
scanf("%29s", &input);
if (strcmp(input, "exit") == 0)
break;
node_t* prev = current;
current = CreateNewNode(prev);
strcpy(&(current->value)[0], input); // strcpy(current->value, input); is fine too
if (head == NULL)
head = current;
}
// clean-up
DestroyNodes(head);
return 0;
}

As mentioned in comments you should use malloc. This is because you want to reserve storage for each new object at the point of creation. Otherwise objects without any linkage (like new in your example) are destroyed at the end of the scope (in the next iteration entering the while loop or at the end of it):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node
{
char value[30];
struct node *next;
};
int main()
{
struct node *current = NULL;
struct node *head = NULL;
while (1)
{
char input[30];
scanf("%29s", &input);
if (strcmp(input, "exit") == 0) break;
struct node *new = malloc(sizeof *new);
strcpy(new->value, input);
if (head == NULL)
{
head = new;
}
else
{
current->next = new;
}
current = new;
}
return 0;
}
Of-course this would create memory leakage but that should not be an issue with this small program since the operating system will automatically free the allocations created.

Related

How to access linked list node from other function?

Hey im trying to make a linked list. I created linked list from other function called CreateLibrary. but then how can I access the head of the node of the linked list from other function?
int *HeadGlobal;
struct node {
char judul[50], author[30];
struct node *link;
};
int CreateLibrary(struct node *head) {
struct node *head = malloc(sizeof(struct node));
HeadGlobal = head;
}
int ViewData() {
char judul[50], author[50];
struct node *head = malloc(sizeof(struct node));
head = &HeadGlobal;
printf("%s dan %s", head->judul, head->author);
}
I tried to make HeadGlobal Pointer and save the head pointer into this global pointer, therefore accessing it from other function,called ViewData(). but I think its not the correct solution. how to solve this?
The name CreateLibrary implies that you should be able to create any number of libraries. You do not need any global variables to achieve that. You are also confusing the type needed to maintain a library. Your linked list should maintain a linked list of struct nodes - not ints.
Here's an example of how that may look:
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct node node; // makes it possible to use `node` instead of `struct node`
struct node {
char judul[50], author[30];
node *link;
};
typedef struct {
node* head;
node* tail;
size_t count;
} library; // library is the type maintaining info about one library instance
// here's the function to create one instance of a library:
library *CreateLibrary() {
library *newlibrary = malloc(sizeof *newlibrary);
if(newlibrary == NULL) return newlibrary;
// initialize this new empty library:
newlibrary->head = NULL;
newlibrary->tail = NULL;
newlibrary->count = 0;
return newlibrary;
}
// a function to clean up:
void DestroyLibrary(library *lib) {
for(node *curr = lib->head, *next; curr != NULL; curr = next) {
next = curr->link;
free(curr);
}
free(lib);
}
// a helper function to create a new node:
node *CreateNode(const char *judul, const char *author) {
node *new_node = malloc(sizeof *new_node);
if(new_node == NULL) return new_node; // oups - this should rarely happen
new_node->link = NULL;
// copy the supplied information into the new node:
strncpy(new_node->judul, judul, sizeof new_node->judul);
new_node->judul[sizeof new_node->judul - 1] = '\0'; // just a precaution
strncpy(new_node->author, author, sizeof new_node->author);
new_node->author[sizeof new_node->author - 1] = '\0'; // just a precaution
return new_node;
}
// a helper function to add a node to the library:
bool AddToLibrary(library *lib, node *new_node) {
if(new_node == NULL) return false; // we won't add node pointers pointing at NULL
if(lib->head == NULL) { // this is the first node added to library
lib->head = new_node;
} else { // there is already at least one node in the library
lib->tail->link = new_node;
}
lib->tail = new_node; // and the new node is the new tail
lib->count++; // increase the number of nodes in the library
return true; // we successfully added the node
}
// print the information about one specific node:
void ViewNode(const node *node) {
printf("%s dan %s\n", node->judul, node->author);
}
// print the information for all nodes in one specific library:
void ViewLibrary(const library *lib) {
for(node *curr = lib->head; curr != NULL; curr = curr->link) {
ViewNode(curr);
}
}
Example usage:
int main() {
library *lib = CreateLibrary();
if(lib == NULL) return 1; // failure :-(
AddToLibrary(lib, CreateNode("foo", "Hello"));
AddToLibrary(lib, CreateNode("bar", "World"));
ViewLibrary(lib);
DestroyLibrary(lib);
}
Demo

Unnecessary Changes being made when appending to linked list

A I have managed to get the linked list to function in the sense that it can create a list store variables in them, but now I have run into another issue that I've never been able find the solution to. Any time I run it through a list of variables I want stored it will run through the list and create the right number of nodes, but the string variable keeps getting changed after each append.
For example if I run:
"Dog" "cat" "house"
Instead of the desired output:
Dog
cat
house
It produces
house
house
house
I'm unsure why it keeps doing it and I can't seem to pin where the head node string is being altered except for the first instance in which the list is empty and thus needs to assign a new head.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#define EMPTY NULL;
typedef struct listnode{
struct listnode* next;
char* fileName;
} listnode;
struct listnode* head;
//This section of code will be dedicated to the creation and management
//of the listnode functions
listnode* createNode(char* str, listnode* next){
listnode* tempo;
tempo = (listnode*)malloc(sizeof(struct listnode));
if(tempo == NULL){
printf("Error creating space for new node.\n");
exit(0);
}
tempo->fileName = str;
tempo->next = next;
return tempo;
}
listnode* append(listnode* head, char* str){
listnode* temp;
listnode* curr;
temp = createNode(str, NULL);
if(head == NULL){
head = temp;
return head;
}
else{
curr = head;
while(curr->next != NULL){
curr = curr->next;
}
curr->next = temp;
return head;
}
}
void printNames(listnode* head){
listnode* curr= head;
while(curr !=NULL){
printf("%s \n", curr->fileName);
curr = curr->next;
}
}
void list_free(listnode* head){
listnode* current;
listnode* temp;
if(head != NULL){
current = head->next;
if(head !=NULL){
current = head -> next;
head ->next = NULL;
while(current != NULL){
temp = current -> next;
free(current);
current = temp;
}
}
}
free(head);
}
int main(int argc, char **argv){
char *current_dir = NULL;
DIR *direct_ptr = NULL;
struct dirent *dir_ptr = NULL;
unsigned int fileNum = 0;
int c;
listnode* head = NULL;
current_dir = getenv("PWD");
if(NULL == current_dir){
printf("\n Error: Couldn't grab current directory.\n");
return -1;
}
direct_ptr = opendir((const char*)current_dir);
if(NULL == direct_ptr){
printf("\n Error: couldn't open current directory\n");
return -1;
}
for(fileNum=0; NULL != (dir_ptr = readdir(direct_ptr)); fileNum++){
if(dir_ptr->d_name[0] != '.'){
head = append(head, dir_ptr->d_name);
}
}
printNames(head);
}
In C, arrays (such as strings) are not passed by value. They are instead passed by pointer. When you specify the a char array as a function parameter, the array decays to a pointer.
Therefore, you must either
ensure that the string that the listnode struct member filename points to remains valid and is not overwritten, or
store a copy of the string in the listnode struct.
In order to copy a string, you can use the function strcpy. However, you must then either allocate enough space for the char array in the listnode struct or you must use dynamic memory allocation (such as malloc) and store a pointer to the dynamically allocated memory.

Getting a segfault with linked list

Apologies for the very basic question, but I can't figure this out. I am trying to build a simple linked list and append some values to it in C.
Below is the list.c file
#include <stdio.h>
#include <stdlib.h>
#include "./list.h"
int main(int argc, char *argv[]) {
int arr[] = {1,2,3,4};
List *list = createList();
int i = 0;
for(i = 0; i < 4; i++) {
appendList(list, arr[i]);
}
return 0;
}
List *createList() {
List *list = malloc(sizeof(List));
if(list == NULL) {
return NULL;
}
list->head = malloc(sizeof(Node));
list->tail = malloc(sizeof(Node));
if(list->head == NULL || list->tail == NULL) {
free(list);
return NULL;
}
list->size = 0;
return list;
}
void appendList(List *list, int num) {
if(list->head->value == 0) {
list->head->value = num;
list->tail->value = num;
return;
}
Node *current = calloc(1, sizeof(Node));
current = list->head;
while(current->next != NULL) {
current = current->next;
}
current->next = calloc(1, sizeof(Node));
if(current->next == NULL) {
free(current->next);
printf("Failed to allocate memory");
exit(1);
}
current->next->value = num;
list->size += 1;
list->tail = current->next;
}
And below is the header file
#ifndef List_h
#define List_h
#include <stdlib.h>
typedef struct node {
int value;
struct node *next;
} Node;
typedef struct {
Node *head;
Node *tail;
int size;
} List;
List *createList();
void appendList(List *, int num);
Node *removeList(List *);
void printList(List *);
#endif
While running through a debugger, my code seems to be working fine, which makes even less sense.
I assume my issue is in the while loop inside of appendList, where I am trying to access some unallocated piece of memory. Is the issue then with the check I am making, current->next != NULL? Does accessing an unallocated piece of memory necessary return NULL?
Hmm, well my thoughts are that you've created the initial head and tail Nodes and you didn't set its value. Later you use value to determine whether or not you need to add another node or set head and tail to the value passed:
void appendList(List *list, int num) {
if(list->head->value == 0) {
list->head->value = num;
list->tail->value = num;
return;
}
...
The memory returned from malloc will not be necessarily zero, so your algorithm should ensure that all values are set before proceeding.
You then proceed to reach the end of your list:
Node *current = calloc(1, sizeof(Node));
current = list->head;
while(current->next != NULL) {
current = current->next;
}
However, again, while list->head exists, you never set the value of list->head->next! Following an unassigned pointer is not going to end nicely for you in the best of cases.
Consider creating a method to create a new node:
Node* createNode() {
Node* node = malloc(sizeof(Node));
if(node == NULL) {
return NULL;
}
node->value = 0;
node->next = NULL;
return node;
}
Also please note that there's a minor correction to the code here (unrelated to your segmentation fault, but could still create memory leak):
list->head = malloc(sizeof(Node));
list->tail = malloc(sizeof(Node));
if(list->head == NULL || list->tail == NULL) {
free(list);
return NULL;
}
Note that it is possible for list->head to correctly be assigned memory and list->tail to not be correctly assigned memory. In that case, you risk having a memory leak for list->head. Please take the necessary precautions.
Especially in embedded systems, the code compiled for debug mode and the one for release mode can differ. So, for me, there is no surprise that your code works in debug and won't in release.
When creating linked lists using malloc, it is possible that the compiler sets the address of your "struct node * next" element, a non-accessible location in memory. So if you try to access it, you'll get a segfault. (or BAD_EXC in MacOS)
If you suspect that malloc is your problem, try creating a small list with no malloc and see if you have segfault, i.e. use:
struct node myNode;
struct node* pmyNode = &myNode;
In your while loop, I suppose, you are trying to go to the last element of your list. So, instead of:
while(current->next != NULL) {
current = current->next;
}
Try to do this:
last_linked_list_element->next = last_linked_list_element;
current = first_linked_list_element;
while(current != current->next) {
current = current->next;
}
You will break out of the loop when you are at the last element of your list.
Another solution would be to try:
last_linked_list_element->next = NULL;
or
last_linked_list_element->next = &random_identifier;
This will make sure that the pointer locates to an accesible location in memory. Does this solve your problem?
In addition to the previous post, in the following code:
Node *current = calloc(1, sizeof(Node));
current = list->head;
while(current->next != NULL) {
current = current->next;
}
you should to delete the line Node *current = calloc(1, sizeof(Node)); because in this way you allocate memory and than don't use it (subsequently you assign currect pointer to another value).

What does each line do in this Linked List program?

Here is a linked list I am working on, and trying to figure out exactly what each line does. The way I seem to be learning how to program is painstakingly difficult, and I am getting extremely discouraged. Regardless, I understand how the link list works, but I am not understanding what the code is saying and what it exactly is doing to create the structs. For example: I can't understand why would you be assigning a pointer to node (13 and 14), especially when my understand of pointers is that they are used to store memory locations.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct numnode
{
int val;
struct numnode * next;
};
typedef struct numnode node;
main()
{
int i;
node * head;
node * newnode;
head = NULL;
for (i = 1; i <= 10; i++)
{
newnode = (node *) malloc(sizeof(node));
newnode->val = i;
newnode->next = NULL;
if (head == NULL)
{
head = newnode;
}
else
{
newnode->next = head;
head = newnode;
}
}
}
Here are some annotations (and minor edits to reduce the amount of code).
/* Linked list node definition */
struct node {
int val;
struct node * next;
};
int main() {
int i;
struct node *head, *new_node;
head = NULL;
for (i = 1; i <= 10; i++) {
// Allocate a new node and initialize its components (val and next)
new_node = (struct node *) malloc(sizeof(node));
new_node->val = i;
new_node->next = NULL;
// The if block is actually not necessary...
if (head == NULL) {
// If the linked list is empty, set the head pointer to the initial node
head = new_node;
} else {
// Now that you have your new node, connect it. Start:
// head->[current linked list]
// [new_node.next]->NULL
new_node->next = head;
// head->[current linked list]->...
// [new_node.next]->[current linked list]->...
head = newnode;
// head->[new_node.next]->[current linked list]->...
}
}
}
The key thing is that malloc returns a pointer to memory. Each new node is allocated dynamically and thus is a location in memory (not a basic type).
If you fix the statement pointed out by PakkuDon you will find that the code inserts at the head. It will end up with a list whose values descend from 9 down to 1.
pointer is just the thing to tell you where is the value,like a phone number,you can call anyone no matter who there is,as you konw the number.pointer can point to anything(under your access) as you want,no matter it is a int or a struct.
Here is the summary of this code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct numnode
{
int val;
struct numnode * next;
};
typedef struct numnode node;
main()
{
int i;
node * head;
node * newnode;
head = NULL;
for (i = 1; i <= 10; i++)
{
newnode = (node *) malloc(sizeof(node));
newnode->val = i;
newnode->next = NULL;
if (head == NULL) // It'll be NULL first time, as head = NULL.
{
// True # i = 1
head = newnode;
}
else // Afterwards, as head=newnode
{
// New node will be created every time. Till i <= 10.
newnode->next = head;
head = newnode;
}
}
}
It is a simple code though.
PS: It is head == NULL

Segmentation fault when freeing String in a Struct - C

I've been stuck on a segmentation fault of a long time. I declared a struct with a pointer to a string. I wrote two functions, create and remove to manipulate values. The struct is as follows:
#include "filename.h"
//*in filename.h:* typedef struct linkNode linkNode_t;
struct linkNode{
struct linkNode *next;
char *value;
};
The create function will first allocate memory for the node, then allocate memory for the value, and then copy the input value into the value field:
linkNode_t* create(char* stuff){
linkNode_t *ptr=malloc(sizeof(linkNode_t));
if(ptr==NULL){
printf("malloc failure");
return NULL;
}
char* tempvalu=malloc(sizeof(char)*strlen(stuff)+1);
if(tempvalu==NULL){
printf("malloc failure");
return NULL;
}
strcpy(tempvalu,stuff);
ptr->next=NULL;
ptr->value=tempvalu;
return ptr;
}
A function is used to insert a node into the linked list:
linkNode_t* insertLast(linkNode_t* start, linkNode_t* newNode){
linkNode_t* current=start;
while(current->next!=NULL){
current=current->next;
}
//now current points to the last element in the linked list
current->next=newNode;
return start;
}
The part causing me problem is as follows:
linkNode_t* removebyValue(linkNode_t* start, char* valu){
/**removes the first instance of a node with a certain value. Return *start after removing.
if linked list becomes empty, return NULL*/
linkNode_t *current=start;
linkNode_t *previous=start;
while(current!=NULL){
if(strcmp(valu,current->value)==0) {//found the node to delete
if(current==start){//removing the head
linkNode_t* retvalue= current->next;
free(current->value);
free(current);
return retvalue;
}
else{ //removing other elements in the linked list
previous->next=current->next;
free(current->value);
free(current);
return start;
}
}
else{
previous=current;
current=current->next;
}
}
return start;
}
In the Main I created a linked list of two elements,1 and 2, and tried to free element 1 when segmentation fault occured.
int main(){
linkNode_t *pt1=create("1");
pt1=insertLast(pt1,create("2"));
removebyValue(pt1,"1"); //Causes seg fault. If I replace "1" by "2" nothing happens
Can someone give some suggestions on this? Thanks in advance
EDIT: I put all the code that could be related since someone said the sections I put on didn't have an error
I think you're over-thinking the removal of a node while maintaining the start pointer properly. Consider a hopefully simpler approach.
typedef struct node_t
{
struct node_t* next;
char* value;
} node_t;
node_t* remove(node_t *start, const char* valu)
{
node_t* current=start;
node_t* prev=NULL;
while(current && strcmp(current->value, valu))
{
prev = current;
current = current->next;
}
if (current)
{
if (prev) // we're not deleting start node
prev->next = current->next;
else // we *are* deleting start node
start = current->next;
// now the node is unlinked. remove it.
free(current->value);
free(current);
}
return start;
}
here's an alternative test code that works fine, take a loot at it and see if it helps.
in addition, you can add
typedef struct node_t {
struct node_t* next;
char* value;
} node;
this may appear simpler to understand, but it isn't because nature of typedef is confusing.
I STRONGLY suggest you take a look at https://github.com/torvalds/linux/blob/master/Documentation/CodingStyle
This is the coding style of the linux kernel, it is very short and simple, not particularly a law, but it is worth noting...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node_t {
struct node_t* next;
char* value;
};
struct node_t* create(const char* istr)
{
struct node_t* ptr = (struct node_t*)malloc(sizeof(struct node_t));
char* tmp = (char*)malloc(sizeof(char) * (strlen(istr) + 1));
strcpy(tmp, istr);
ptr->next = 0;
ptr->value = tmp;
return ptr;
}
struct node_t* remove(struct node_t* start, const char* value)
{
struct node_t* current = start;
struct node_t* prev = start;
while (current != 0) {
if (!strcmp(value, current->value)) {
if (current == start) {
struct node_t* retval = current->next;
free(current->value);
free(current);
return retval;
} else {
/* nothing happens */
return 0;
}
}
}
}
int main(const int argc, const char** argv)
{
struct node_t* pt = create("1");
printf("%s\n", pt->value);
pt->next = create("2");
printf("%s\n", pt->next->value);
remove(pt, "1");
return 0;
}

Resources