C Linked List Head Pointer is changing data value [closed] - c

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am writing a custom shell for class. I have the shell working but now I need to keep track of which commands are called by the user in a linked list, and then be able to print out these commands in a similar fashion to the history() command. The program seems to build the linked list fine however upon printing out with history(list) I begin to see errors. After several commands are entered the command and string data values for the nodes begin to change. I have checked to make sure that the addresses the pointers are pointing to stay the same, but somehow the data values are being effected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct Node{
char* command;
char* string;
struct Node *next;
};
struct List{
struct Node* front;
struct Node* rear;
};
void shell_loop(void);
char *read_input(void);
char **split_input(char *input);
struct Node* createNode(char* command, char* string);
struct List* createList();
struct List* add_to_end(struct List *Q, char* command, char* string);
void history(struct List* Q);
const int TOKEN_BUFSIZE = 64;
const char* DELIMITER = " \t\r\n\a";
//#define EXIT_FAILURE
int main(int argc, char **argv)
{
shell_loop();
}
void shell_loop(void)
{
char *input;
char **arguments;
char* command;
char* string;
struct List* list = createList();
for(int i =0; i < 20; i++)
{
printf("User> ");
input = read_input();
arguments = split_input(input);
command = arguments[0];
string = arguments[1];
list = add_to_end(list, command, string);
printf("\n");
history(list);
printf("\n");
free(input);
free(arguments);
}
}
char *read_input(void)
{
char* input;
size_t bufsize = 1000;
getline(&input, &bufsize, stdin);
return input;
}
char **split_input(char *input)
{
int size_of_buffer = TOKEN_BUFSIZE, position = 0;
char **tokens = malloc(size_of_buffer * sizeof(char*));
char *token;
if(!tokens)
{
fprintf(stderr, "shell: allocation error\n");
exit(1); // fix later
}
token = strtok(input, DELIMITER);
while (token != NULL)
{
tokens[position] = token;
position ++;
if(position >= size_of_buffer)
{
size_of_buffer += TOKEN_BUFSIZE;
tokens = realloc(tokens, size_of_buffer * sizeof(char*));
if(!tokens)
{
fprintf(stderr, "shell: allocation error \n");
exit(EXIT_FAILURE); // fix later
}
}
token = strtok(NULL, DELIMITER);
}
tokens[position] = NULL;
return tokens;
}
struct Node* createNode(char* c, char* s)
{
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
temp->command = c;
temp->string = s;
temp->next = NULL;
return temp;
}
struct List* createList()
{
struct List* Q = (struct List*)malloc(sizeof(struct List));
Q->front = NULL;
Q->rear = NULL;
return Q;
}
struct List* add_to_end(struct List *Q, char* c, char* s)
{
struct Node* temp = createNode(c, s);
if(Q->front == NULL)
{
Q->front = temp;
Q->rear = temp;
temp = NULL;
return Q;
}
Q->rear->next = temp;
Q->rear = temp;
temp = NULL;
return Q;
}
void history(struct List* Q)
{
struct Node* current;
if (Q->front == NULL)
{
printf("Command List is empty!\n");
return;
}
current = Q->front;
while(current !=NULL)
{
printf("Command: %s\nString: %s\n", current->command, current->string);
current = current->next;
}
}
I have attached an output file of the history command to highlight how the first entered command eventually changes:

you are just shuffling pointer to stack data around, you need to copy the actual strings
command = strdup(arguments[0]);
string = strdup(arguments[1]);

I think you want temp->string = strdup(s) in createNode(...) instead of temp->string = s

Your call to getline is wrong.
If *lineptr is set to NULL and *n is set 0 before the call, then
getline() will allocate a buffer for storing the line. This buffer
should be freed by the user program. ... Alternatively, before calling getline(), *lineptr can contain a
pointer to a malloc(3)-allocated buffer *n bytes in size
Since *n is 1000 and input is uninitialized (points nowhere), getline assumes there is a buffer of 1000 chars available...which isn't.
Your call should be:
char *read_input(void)
{
char* input= 0;
size_t bufsize = 0;
getline(&input, &bufsize, stdin);
return input;
}
See the comments and other solutions for the other problems of your program.

Related

Creating a singly linked list from a .txt file and reversing odd numbers of each line in C

I have a project about linked lists but I'm having a hard time doing it. The teacher wants me to read a .txt file and create singly linked list from it. After that, I need to reverse odd numbers of every line. Then print it. Here is the code which I used for printing the linked list. But I need help to reverse the odd numbers of each line.
This is the code which I used to print the list:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
char *string;
struct list *next;
};
typedef struct list LIST;
int main(void) {
FILE *fp;
char line[10];
LIST *current, *head;
head = current = NULL;
fp = fopen("data.txt", "r");
while(fgets(line, sizeof(line), fp)){
LIST *node = malloc(sizeof(LIST));
node->string = strdup(line);
node->next =NULL;
if(head == NULL){
current = head = node;
} else {
current = current->next = node;
}
}
fclose(fp);
for(current = head; current ; current=current->next){
printf("%s", current->string);
}
return 0;
}
Here is the content of the .txt file:
10
9,6,11,7,12,18,19,14,15,13
13,14,9,12,15,3,18,20,1,2
4,11,8,17,12,15,20,10,3,16
19,4,11,1,13,17,12,16,20,18
1,6,20,11,13,9,7,16,10,2
12,4,11,16,3,20,9,19,17,15
20,3,10,12,18,2,5,14,15,16
18,19,15,2,6,9,1,3,17,4
7,6,20,1,11,4,3,5,8,16
1,2,16,13,17,10,12,9,4,15
"But I need help to reverse the odd numbers of each line."
There are several other parts that need to be considered before this step can be developed.
Following are suggestions for a functions approach implementation using your problem description. A few items are simply suggestions to simplify the existing code. And a few other steps, are not mentioned as necessary, but should be considered:
Since you are not mandated to use char *string; in your problem description, choose to use a reasonable string length variable that does not require an additional layer of dynamic allocation, such as char string[260]; (or even smaller to fit your input file.) This will greatly simplify the code.
Because the input file is sized with lines ~30 char long, declare the variable line to be at least large enough to contain one line, eg 80 would allow larger values, and still allow enough space, but since memory is cheap, go with the same size as is used in the string member of your linked list.
Move the work of populating each new node to a function. It also will greatly simplify the program, and provide greater readability. Eg: void insert(LIST **head_ref, char *str);
Always test the return of fopen() before attempting to use the file descriptor.
To manipulate the contents of each odd row (eg 1, 3, 5, 7, 9), as numbers, the contents of each line read in from a file as a string, needs to first be converted to a collection of numbers. This suggests an additional member be added to the struct. For example int num[10].
The previous observation implicitly suggests the need of an additional function to parse and convert each comma delimited string into discrete integer values. Perhaps with the prototype: void parseIntArray(LIST **list);
The next and final task also suggests an additional function to reverse the contents of selected array member integer arrays. This one might use a prototype such as: void reverse_odd(LIST **list, size_t size);
Finally, because each node of LIST created required dynamically allocated memory, once finished using LIST, the memory must be given back to the OS to prevent memory leaks. An additional function to do this could be prototyped: void freeList(LIST **head);
Following are the main() function and preceding support declarations etc. It is intended here to illustrate the above suggested steps, and the benefits of breaking down a bigger problem into smaller problems, then implementing each smaller solution to support the whole. Benefits include for example readability and maintainability and potential re-use of code-base, (Note the similarity of argument lists in each supporting function.):
#define MAX_STRLEN 260 //use mnemonic values to avoid magic numbers in code
struct list {
char string[MAX_STRLEN];
int arr[10];
struct list *next;
};
typedef struct list LIST;
//Prototypes of 'smaller' solutions
void insert(LIST **head_ref, char *str);
void parseIntArray(LIST **list);
void reverse_odd(LIST **list, size_t size);
void freeList(LIST **head);
int main(void)
{
FILE *fp;
char line[MAX_STRLEN];
LIST *current, *head;
char *convPtr = NULL;
head = current = NULL;
fp = fopen("data.txt", "r");
if(fp)
{
//consume 1st line
if(fgets(line, sizeof(line), fp));//10
{
sizeArray = strtol(line, &convPtr, 10);
if(errno != ERANGE)
{
while(fgets(line, sizeof(line), fp))
{
//(see implementations of each below)
//create new node, insert num string
insert(&current, line);
//convert new->string to integers, place in new->array
parseIntArray(&current);
//reverse 'odd' contents of each array
reverse_odd(&current, sizeArray);
}
}else{//handle error and leave}
}
fclose(fp);
}else{//handle error and leave}
//At this point in code, entire file is captured into nodes of list.
//use list as needed
//When finished using list, memory must be freed to prevent memory leaks
head = current;
freeList(&head);
return 0;
}
The remaining code segments are the function implementations used above:
void freeList(LIST **head)
{
LIST *tmp;
while (*head != NULL)
{
tmp = (*head);
(*head) = (*head)->next;
free(tmp);
}
}
//create new node, insert num string
void insert(LIST **head_ref, char *str)
{
int *arr = malloc(numNodes * sizeof(*arr));
//allocate node
LIST* new = calloc(1, sizeof(*new));
//put in the data
strcpy(new->string, str);
//Make next of new node as head
new->next = (*head_ref);
//Move the head to point to the new node
(*head_ref) = new;
}
//convert new->string to integers, place in list->array
void parseIntArray(LIST **list)
{
char *tok = NULL;
int i = 0;
int tmp = 0;
char *sArray = strdup((*list)->string);
tok = strtok(sArray, ",\n ");
while(tok)
{
errno = 0;
tmp = atoi(tok);
if(errno == ERANGE)
{
printf("Error converting string to number\nExiting.");
return;
}
(*list)->arr[i] = tmp;
i++;
tok = strtok(NULL, ",\n ");
}
}
//reverse 'odd' contents of list->array
void reverse_odd(LIST **list, size_t size)
{
int *ptr = &((*list)->arr[0]);
int *tmp = malloc(size * sizeof(*tmp));
memset(tmp, -1, size*sizeof(*tmp));
for(int i=0;i<size;i++)
{
if(ptr[i]%2 != 0)
tmp[size-1-i] = ptr[i];
}
for(int i=0;i<size;i++)
{
if(tmp[i] < 0)
{
while((*ptr)%2 != 0 ) ptr++;
tmp[i] = *ptr;
ptr++;
}
}
memcpy((*list)->arr, tmp, size*sizeof(int));
}
This hope this code will do the job.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct line {
struct num *first;
struct line *next;
} LineNode;
typedef struct num {
int num;
int order;
struct num *next;
} NumNode;
int main() {
FILE *fp;
char ch;
int counter = 0;
NumNode *curr_num, *even_ptr, *odd_ptr, *odd_head, *even_head;
LineNode *curr_line, *line_head;
curr_num = even_head = odd_head = even_ptr = odd_ptr = NULL;
line_head = curr_line = NULL;
fp = fopen("data.txt", "r");
if (fp == NULL)
{
return 1;
}
ch = fgetc(fp);
while(ch != EOF){
if (ch >= 48 && ch <= 57)
{
int n = 0;
while (ch != EOF && ch != '\n' && ch >= 48 && ch <= 57)
{
int x = ch - 48;
n = n * 10 + x;
ch = fgetc(fp);
}
NumNode *node = malloc(sizeof(NumNode));
node->num = n;
node->order = counter;
node->next =NULL;
if (n % 2 == 0){
if(even_head == NULL){
even_head = even_ptr = node;
} else {
even_ptr = even_ptr->next = node;
}
}else{
if(odd_head == NULL){
odd_head = node;
} else {
node->next = odd_head;
odd_head = node;
}
}
counter++;
}
if (ch == '\n' || ch == EOF)
{
NumNode *num_node, *head;
num_node = head = NULL;
even_ptr = even_head;
odd_ptr = odd_head;
counter = 0;
if (even_head != NULL && even_head->order == counter){
head = num_node = even_ptr;
even_ptr = even_ptr->next;
} else {
head = num_node = odd_ptr;
odd_ptr = odd_ptr->next;
}
counter++;
while (even_ptr != NULL)
{
if (even_ptr->order == counter) {
num_node = num_node->next = even_ptr;
even_ptr = even_ptr->next;
}
else if (odd_ptr != NULL) {
num_node = num_node->next = odd_ptr;
odd_ptr = odd_ptr->next;
}
counter++;
}
while (odd_ptr != NULL)
{
num_node = num_node->next = odd_ptr;
odd_ptr = odd_ptr->next;
}
LineNode *node = malloc(sizeof(LineNode));
node->next =NULL;
node->first = head;
if (line_head == NULL)
line_head = curr_line = node;
else
curr_line = curr_line->next = node;
odd_head = even_head = NULL;
counter = 0;
}
ch = fgetc(fp);
}
fclose(fp);
for(curr_line = line_head; curr_line != NULL ; curr_line=curr_line->next) {
for(curr_num = curr_line->first; curr_num != NULL ; curr_num=curr_num->next) {
printf("%d", curr_num->num);
if (curr_num->next != NULL)
printf(",");
}
printf("\n");
}
return 0;
}

How to store values with same memory location in c?

If I have a file stream with content
123 1234
1223 124235
21432 325
In my program I read line by line of the file and store the first target of each line into my list. These line with same location and when I run the program it will keep pointing to the most recent data and place it in to list. Which means If I have a function called printL() in while loop. It will print
123/
1223/1223/
21432/21432/21432/
instead of
123/
123/1223/
123/1223/21432
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct n{
char *value;
struct n *next;
} Node;
void printList(Node *head){
Node *cur = head;
while(cur!=NULL){
printf("%s/", cur->value);
cur = cur->next;
}
printf("\n");
}
void insertIntoList(Node **head, char *data){
Node *newNode = malloc(sizeof(Node));
if (newNode == NULL){
perror("Failed to allocate a new node for the linked list");
exit(1);
}
newNode->value = data;
newNode->next = NULL;
Node *currentList = *head;
if(*head == NULL){ //if the linked list head is null, then add the target into linked list
*head = newNode;
}
else{
while(currentList->next!=NULL){
currentList = currentList->next;
}
currentList->next = newNode;
}
}
int main(int argc, char**argv){
FILE *fileStream;
size_t len = 0;
char *line = NULL;
Node *head = NULL;
int j;
for(j=1; j<argc-2;j++){
fileStream = fopen(argv[j], "r");
if(fileStream == NULL){
fprintf(stderr, "could not open");
continue;
}
insertIntoList(&head,"a"); /////////////Line 95
insertIntoList(&head,"b");
insertIntoList(&head,"c");
insertIntoList(&head,"d");
printf("here is a try\n");
printList(head);
while(getline(&line, &len, fileStream)!=EOF){ /////////////Line 101
char *targetNum = strtok(line, " \t\r\n");
printf("*****%s\n", targetNum);
insertIntoList(&head, targetNum);
printf("######print head here is##########\n");
printList(head);
printf("######print head here is##########->\n");
}
//printList(head);
}
return 0;
}
In order to keep the content of each loaded field returned from strtok(), just add a strdup() before calling insertIntoList() after checking if not a null-pointer.
In your code, if you compare the value of both line and targetNum
are the same. If fact, the strtok() function returns a pointer to
the input string and keep the pointer for the next argument.
Replace the following code:
char *targetNum = strtok(line, " \t\r\n");
printf("*****%s\n", targetNum);
insertIntoList(&head, targetNum);
By that one:
char *targetNum = strtok(line, " \t\r\n");
if (targetNum != NULL) {
printf("*****%s\n", targetNum);
insertIntoList(&head, strdup(targetNum));
}
You don't store the contents of the string in your list nodes; you store a pointer to the buffer used for the contents of the string.
Consider changing your list node structure to
typedef struct node Node;
struct node {
Node *next;
char data[];
};
where the contents of the string are stored in the C99 flexible array member.
Your node constructor is then something like
Node *new_node(const char *data)
{
const size_t datalen = (data) ? strlen(data) : 0;
Node *result;
result = malloc(sizeof (Node) + datalen + 1);
if (!result) {
fprintf(stderr, "Out of memory!\n");
exit(EXIT_FAILURE);
}
if (datalen > 0)
memcpy(result->data, data, datalen);
result->next = NULL;
result->data[datalen] = '\0';
return result;
}
See how the function allocates memory for the copy of the data?
Personally, I prefer something like
typedef struct node Node;
struct node {
Node *next;
size_t hash;
size_t size;
char data[];
};
where the size member is basically strlen(data) (except that you can also use the nodes to hold binary data that includes nul bytes \0), and hash is a simple hash computed from data. hash is useful if you intend to compare the entire contents of nodes; if two nodes' lengths or hashes differ, then it is certain their contents differ; if they are the same, then you compare them character by character (memcmp(node1->data, node2->data, node1->length) == 0 if they are the same).
The constructor for the above is something like (using DJB2 hash):
Node *new_node(Node *next, const void *data, const size_t size)
{
Node *result;
result = malloc(sizeof (Node) + size + 1);
if (!result) {
fprintf(stderr, "new_node(): Out of memory (%zu bytes)\n", size);
exit(EXIT_FAILURE);
}
/* Copy and hash data using DJB2 hash (not that good, but fast) */
{
unsigned char *src = (unsigned char *)data;
unsigned char *const end = (unsigned char *)data + size;
unsigned char *dst = result->data;
size_t hash = 5381;
while (src < end) {
hash = hash * 33 + (size_t)(*src);
*(dst++) = *(src++);
}
/* Add terminator */
*dst = '\0';
}
result->next = next;
result->hash = hash;
result->size = size;
return result;
}
These Nodes can also be used in e.g. hash tables, which makes the type quite versatile.

C: Variable is uninitialized for linked list

I'm relatively new to C and I was creating a program that involves a linked-list. Here is a very abbreviated version of the code that's giving me trouble.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define STRLEN 100
struct Gene {
int num[4];
struct Gene *next;
};
typedef struct Gene item;
void build_list(item *current, item *head, FILE *in);
int main() {
FILE *input;
FILE *output;
input = fopen("test.data", "r");
output = fopen("test.out", "w+");
item *curr;
item *head;
head = NULL;
int i;
build_list(curr, head, input);
curr = head;
while(curr) {
for (i = 0; i < 4; ++i)
fprintf(output, "%d\n", curr->num[i]);
curr = curr->next;
}
fclose(input);
fclose(output);
free(curr);
}
void build_list(item *current, item *head, FILE *in) {
char gene[STRLEN];
char *tok;
char gene_name[STRLEN];
char *search = ",";
int j;
while (fgets(gene, sizeof(gene), in)) {
current = (item *)malloc(sizeof(item));
tok = strtok(gene, search);
strcpy(gene_name, tok);
for (j = 0; j < 4; ++j) {
tok = strtok(NULL, search);
current->num[j] = atoi(tok);
}
current->next = head;
head = current;
}
}
When I try to compile this, it says variable curr is uninitialized, but even when I initialize it with malloc it throws a segmentation fault, or it prints out nothing at all. Why could this be?
C uses pass by value for function argument passing. So, when you call build_list(curr, head, input);, curr and head themselves are passed by value and any changes made to those variables (corresponding parameters) will not reflect back to the caller.
So, in the caller,
while(curr)
is accessing unitialized variable (meeory) which invokes undefined behavior.
If you need to change curr and head themselves, you need to pass their address and make chages inside the funtion. Something like
build_list(&curr, &head, input);
and
void build_list(item **current, item **head, FILE *in)
and
*current = malloc(sizeof(item));
may get the job done for you.
#Sourav Ghosh have already explained what was wrong with your code and also suggested one way to solve it. Here is another way.
Instead of passing current and head as variables to be changed inside the function (i.e. as pointer-to-pointer), I would recommend that you use the function return value. In that way you don't have to use pointer-to-pointer.
Something like:
item* add_item(item* head)
{
// Place a new item in front
item* current = malloc(sizeof(item));
current->next = head;
return current;
}
item* build_list(item* head, FILE *in) {
char gene[STRLEN];
char *tok;
char gene_name[STRLEN];
char *search = ",";
int j;
while (fgets(gene, sizeof(gene), in))
{
// Get a new item
head = add_item(head);
// Fill data into the new item
tok = strtok(gene, search);
strcpy(gene_name, tok);
for (j = 0; j < 4; ++j)
{
tok = strtok(NULL, search);
head->num[j] = atoi(tok);
}
}
return head;
}
and from maincall it like:
head = NULL;
head = build_list(head, input);
Note: For readability, I skipped all check for failing malloc. In real code you should always check whether malloc returned NULL.

Need to Merge Sort a Linked List of names

I need help with my merge sort function that is a linke list of names. I get a seg fault when I run the program, and I feel like something isnt right. Thanks for the help in advance.
The program is supposed to print out the list of names before sorting, then the list of names after sorting.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
#define MAX_STR_LEN 25
typedef struct Data_ {
char *name;
struct Data_ *next;
}Data;
void split_in_half(Data *source, Data **frontRef,Data **backRef);
Data* merge(Data *a, Data *b);
void merge_sort(Data **list);
Data* read_from_file(const char* file, const int size);
void display(Data *list);
void push(Data **head, char *name);
int main(int argc, char **argv){
if(argc != 2){
printf("Not enough parameters!");
exit(0);
}
Data *head = NULL;
int size = 10;
head = read_from_file(argv[1], size);
printf("\nBefore sort");
display(head);
printf("\nMerge Sort\n");
merge_sort(&head);
display(head);
}
void merge_sort(Data **list){
Data *head = *list;
Data *temp;
Data *temp2;
if((head == NULL) || (head->next == NULL))
{
return;
}
split_in_half(head, &temp, &temp2);
head = merge(temp, temp2);
}
Data *merge(Data *a, Data *b){
Data *result = NULL;
if(a == NULL)
return(b);
else if(b==NULL)
return (a);
if(strcmp(a->name, b->name) > 0)
{
result = a;
result->next = merge(a->next, b);
}
else
{
result = b;
result->next = merge(a, b->next);
}
return (result);
}
void split_in_half(Data *source, Data **frontRef,Data **backRef){
Data *fast;
Data *slow;
if(source == NULL || source->next == NULL)
{
*frontRef = source;
*backRef = NULL;
}
else
{
slow = source;
fast = source->next;
while(fast != NULL)
{
fast = fast->next;
if(fast != NULL)
{
slow = slow->next;
fast = fast->next;
}
}
}
*frontRef = source;
*backRef = slow->next;
slow->next = NULL;
}
void push(Data **head, char *name){
Data *temp = malloc(sizeof(Data));
temp->name = strdup(name);
temp->next = *head;
*head = temp;
}
Data* read_from_file(const char* file, const int size){
FILE *input;
input = fopen(file, "r");
Data *new_ = (Data*)malloc(sizeof(Data*));
new_->next = NULL;
int i;
char name[MAX_STR_LEN];
for(i = 0; i < size; i++){
fscanf(input, "%24s", &name);
push(&new_, name);
}
return new_;
}
void display(Data *list){
Data *current = list;
while(current->next != NULL){
printf("\n%s", current->name);
current = current->next;
}
}
The file that I read in is a list of names. It is:
Derek
Drew
Randell
Terrell
Carmen
Colin
Eddy
Pablo
Lamont
Dexter
In read_from_file you have:
Data *new_ = (Data*)malloc(sizeof(Data*));
new_->next = NULL;
However, you have only allocated space for a pointer, rather than allocated space for a Data structure. So you will be writing off the end of the allocated space in the second line above.
Instead, write:
Data *new_ = (Data*)malloc(sizeof(Data));
new_->next = NULL;
[ You can read about the cons of casting the result of malloc at Do I cast the result of malloc?, but I am just making the minimal change for progress above ]
Once you've made the fix above, try walking through the program in a debugger, or adding printf statements, so you can see exactly how the program is behaving, and understand where any other problems occur.

C Program: Create Linked List Using argv, argc, Segmentation Fault

I have a program that takes in strings using the command line prompts argv and argc. I keep getting a segmentation fault when I go to run the code and after much researching, I cannot determine what might be causing this. Maybe how I execute the code is the issue? I am using gcc -o code code.c then ./code one two three with one two three being the strings added to the linked list. Any assistance in determining where my error might be would be great.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct list_node_s{
char the_char;
struct list_node_s *next_node;
}list_node;
void insert_node(list_node *the_head, char the_char);
void print_list(list_node *the_head);
int main(int argc, char *argv[]){
char next_char;
list_node *the_head = NULL;
insert_node(the_head, next_char);
the_head->next_node = malloc(sizeof(list_node));
if(the_head == NULL){
return 1;
}
the_head->the_char = 1;
the_head->next_node == NULL;
int the_count, the_count2;
for(the_count = 0; the_count < sizeof(argv); the_count++){
for(the_count2 = 0; argv[the_count][the_count2] != '\0'; the_count2++){
next_char = argv[the_count][the_count2];
insert_node(the_head, next_char);
}
}
print_list(the_head);
return (0);
}
void insert_node(list_node *the_head, char the_char){
list_node * current_node = the_head;
while (current_node->next_node != NULL) {
current_node = current_node->next_node;
}
current_node->next_node = malloc(sizeof(list_node));
current_node->next_node->the_char = the_char;
current_node->next_node->next_node = NULL;
}
void print_list(list_node *the_head){
if(the_head == NULL){
printf("\n");
}else{
printf("%c", the_head->the_char);
print_list(the_head->next_node);
}
}
Change this:
list_node *the_head = NULL;
insert_node(the_head, next_char);
the_head->next_node = malloc(sizeof(list_node));
to:
list_node the_head = { '\0', NULL };
to initialize the_head to an empty node.
One problem is in this function:
void insert_node(list_node *the_head, char the_char){
list_node * current_node = the_head;
while (current_node->next_node != NULL) {
current_node = current_node->next_node;
}
current_node->next_node = malloc(sizeof(list_node));
current_node->next_node->the_char = the_char;
current_node->next_node->next_node = NULL;
}
When you call it in main you're basically passing in NULL because you're setting the_head to NULL. You're trying to access current_node->next_node in the while loop conditions, but because of what you're passing in, you're basically doing NULL->next_node.
You need to initialize your head to an empty list_node. Basically since you're using a char as your node element you could set the value of the char to 0x00, which would make it a zero byte. Then that way you know that when you're at that value, you're at the head.
I don't mean to self-promote, but if you want to look at some code for this have a look at this github repo for the Barry_CS-331 Data Structures class. There's C and C++ in there for the Data Structures. I think it might have a list but if not you can use the stack and the queue as an overall example.
I have modified you code, there has some bugs:
1)、the key bug is in this code.
for(the_count = 0; the_count < sizeof(argv); the_count++)
{
for(the_count2 = 0; argv[the_count][the_count2] != '\0'; the_count2++)
{
next_char = argv[the_count][the_count2];
insert_node(the_head, next_char);
}
}
there some bugs:
you cann't use the_count < sizeof(argv), because of the type of argv is char* []; so sizeof(argv) maybe 4 or 8, based on your os.
the right is:
for(the_count = 1; the_count < argc; the_count++){
for(the_count2 = 0; argv[the_count][the_count2] != '\0'; the_count2++){
next_char = argv[the_count][the_count2];
insert_node(the_head, next_char);
}
}
2、this code aose has some bugs:
list_node *the_head = NULL;
insert_node(the_head, next_char);
the_head->next_node = malloc(sizeof(list_node));
if(the_head == NULL){
return 1;
}
the_head->the_char = 1;
the_head->next_node == NULL;
insert_node(the_head, next_char); is no need, you'd better do the_head->the_char = '\0', because of char 1 is no printable character.
One way:
#include <stdio.h>
#include <stdlib.h>
typedef struct list_node_s{
char the_char;
struct list_node_s *next_node;
}list_node;
void insert_node(list_node *the_head, char the_char);
void print_list(list_node *the_head);
int main(int argc, char *argv[]){
list_node *the_head = NULL;
int the_count, the_count2;
for(the_count = 0; the_count < argc; the_count++)
{
for(the_count2 = 0; the_count2 < strlen(argv[the_count]); the_count2++)
insert_node(&the_head, argv[the_count][the_count2]);
}
print_list(the_head);
return (0);
}
void insert_node(list_node **the_head, char the_char){
list_node *new_node;
list_node *tail_node;
/* Allocate and populate a new node. */
new_node = malloc(sizeof(list_node));
new_node->the_char = the_char;
new_node->next_node = NULL;
/* Is the_head already initialized? */
if(*the_head)
{
/* Yes... find the tail_node. */
tail_node = *the_head;
while(tail_node->next)
tail_node = tail_node->next;
/* Append the new_node to the end of the list. */
tail_node->next = new_node;
return;
}
/* the_head was not initialized. The new_node will be the head node. */
*the_head = new_node;
return;
}
void print_list(list_node *the_head){
if(the_head == NULL){
printf("\n");
}else{
printf("%c", the_head->the_char);
print_list(the_head->next_node);
}
}

Resources