snippetcMinor
C program to create and print a linked list from the command line
Viewed 0 times
thecreatelineprogramprintandlistfromlinkedcommand
Problem
This program will create a linked list, set the values, and print the list by using command line options.
This is my first implementation of a linked list so I'm not sure if I did it correctly. The available options are:
To add several nodes:
I'm not looking for any specific input, style, comments, functions used, anything.
```
#include
#include
#include
#include
struct node{
int value;
struct node *next_ptr;
};
struct node *head;
void add_node(int data);
void print_nodes(void);
int main(int argc, char *argv[]){
int c;
long node_value;
char *ptr;
char *token;
const char s[2] = " "; /Split optarg based on this string/
while((c = getopt(argc, argv, "pa:")) != EOF){
switch(c){
case 'p':
print_nodes();
break;
case 'a':
token = strtok(optarg, s); /Split the string/
while(token != NULL){
node_value = strtol(token, &ptr, 10); /Convert each string to integer/
if((ptr) != 10 && (ptr) != 0){ /If it's not a newline or a null then invalid input/
fprintf(stderr, "Invalid number: %c", *ptr);
exit(EXIT_FAILURE);
}
add_node(node_value);
token = strtok(NULL, s);
}
break;
default:
fprintf(stderr, "Unknown option %c, available options are '-p' and 'a'", c);
break;
}
}
argc -= optind;
argv += optind;
return 0;
}
void add_node(int data){
struct node *temp = head;
if(temp == NULL){
head = malloc(sizeof(struct node));
head->value = data;
head->next_ptr = NULL;
return;
}
while(temp->next_ptr != NULL){
temp = temp->next_ptr;
}
This is my first implementation of a linked list so I'm not sure if I did it correctly. The available options are:
-a to add nodes. To add several nodes:
-a "23 56 1" will add three nodes with the respective values-p will print the nodes. It has to be used after -a or else it will result in an error message.I'm not looking for any specific input, style, comments, functions used, anything.
```
#include
#include
#include
#include
struct node{
int value;
struct node *next_ptr;
};
struct node *head;
void add_node(int data);
void print_nodes(void);
int main(int argc, char *argv[]){
int c;
long node_value;
char *ptr;
char *token;
const char s[2] = " "; /Split optarg based on this string/
while((c = getopt(argc, argv, "pa:")) != EOF){
switch(c){
case 'p':
print_nodes();
break;
case 'a':
token = strtok(optarg, s); /Split the string/
while(token != NULL){
node_value = strtol(token, &ptr, 10); /Convert each string to integer/
if((ptr) != 10 && (ptr) != 0){ /If it's not a newline or a null then invalid input/
fprintf(stderr, "Invalid number: %c", *ptr);
exit(EXIT_FAILURE);
}
add_node(node_value);
token = strtok(NULL, s);
}
break;
default:
fprintf(stderr, "Unknown option %c, available options are '-p' and 'a'", c);
break;
}
}
argc -= optind;
argv += optind;
return 0;
}
void add_node(int data){
struct node *temp = head;
if(temp == NULL){
head = malloc(sizeof(struct node));
head->value = data;
head->next_ptr = NULL;
return;
}
while(temp->next_ptr != NULL){
temp = temp->next_ptr;
}
Solution
Nice formatting, good variable and function names. I learned more about
Using Typedef
If the code used typedef for the definition of node, the code might be slightly shorter and more readable:
By using typedef a new type is created. This also might decrease the possibility of future errors by forgetting to put the struct in at some point. This stackoverflow question discusses why it might be good to use typedef.
Global Variables
Generally the use of global variables are frowned upon. When creating, reading and debugging code global variables can be affected by side affects and it can be very difficult to find where the problem is actually occurring. This stackoverflow question talks about when it is proper to use global variables.
It might be better if the global variable
Passing head into each of the functions would make the following changed necessary:
This example might make the program safer and easier to debug and read.
Implicit Type Conversion
My compiler flagged the following line as an implicit type conversion:
because node_value is declared as a long rather than int,
If node_value needs to be a long because that's what
The actual warning message I get is
Functions that might be helpful
To implement a full linked list program some functions that might be helpful are:
Use of the exit() Function
The use of the
consequences (shut down).
The C programming language was originally created to implement operating
systems and in some cases is still used for that purpose. While C doesn't have the exception throwing capabilities of C++, Java, C# and other more modern languages errors can be handled, either by returning error codes or using setjmp() and longjmp().
getopt() from the program (I used to have to write my own command line parsers)! Good use of system macros such as EXIT_FAILURE.Using Typedef
If the code used typedef for the definition of node, the code might be slightly shorter and more readable:
typedef struct node{
int value;
struct node *next_ptr;
} Node;
Node *head;
void add_node(int data){
Node* temp = head;
/* ... */
}
void print_nodes(void){
Node* temp = head;
/* ... */
}By using typedef a new type is created. This also might decrease the possibility of future errors by forgetting to put the struct in at some point. This stackoverflow question discusses why it might be good to use typedef.
Global Variables
Generally the use of global variables are frowned upon. When creating, reading and debugging code global variables can be affected by side affects and it can be very difficult to find where the problem is actually occurring. This stackoverflow question talks about when it is proper to use global variables.
It might be better if the global variable
NODE *head was declared in main() and then passed by reference into each function that modified it, and passed by value into each function that only used it and didn't change it.Passing head into each of the functions would make the following changed necessary:
case 'p':
/*+>*/ print_nodes(head); /* Pass by value */
break;
while(token != NULL){
node_value = strtol(token, &ptr, 10); /*Convert each string to integer*/
if((*ptr) != 10 && (*ptr) != 0){ /*If it's not a newline or a null then invalid input*/
fprintf(stderr, "Invalid number: %c", *ptr);
exit(EXIT_FAILURE);
}
/* ++> */ add_node(node_value, &head); /* Pass by reference */
token = strtok(NULL, s);
}
void add_node(int data, Node **head){
Node* temp;
if(*head == NULL){
*head = malloc(sizeof(struct node));
(*head)->value = data;
(*head)->next_ptr = NULL;
return;
}
temp = *head;
while(temp->next_ptr != NULL){
temp = temp->next_ptr;
}
if((temp->next_ptr = malloc(sizeof(struct node))) == NULL){
fprintf(stderr, "Out of memory");
exit(EXIT_FAILURE);
}
temp = temp->next_ptr;
temp->value = data;
temp->next_ptr = NULL;
}
void print_nodes(Node* head){
Node* temp = head;
if(temp == NULL){
printf("Linked list is empty\n");
}
for(temp = head; temp != NULL; temp = temp->next_ptr){
printf("%i\n", temp->value);
}
}This example might make the program safer and easier to debug and read.
Implicit Type Conversion
My compiler flagged the following line as an implicit type conversion:
add_node(node_value);because node_value is declared as a long rather than int,
long node_value;
void add_node(int data) { /* ... */If node_value needs to be a long because that's what
strtok() is returning, it might be better to either change the input type for add_node() or to explicitly cast node_value in the call:add_node((int) node_value);The actual warning message I get is
implicit conversion loses integer precision: 'long to int' (Xcode 8.2 on El Capitan).Functions that might be helpful
To implement a full linked list program some functions that might be helpful are:
NodePointer new_node(int value);
NodePointer delete_node_by_value(int value, NodePointer head);
NodePointer delete_node_by_pointer(NodePointer delete_target, NodePointer head);
NodePointer find_node(int value, NodePointer head);
void print_node(int value, NodePointer head); // called by print_nodesUse of the exit() Function
The use of the
exit() function can be problematic, in a large software system that one is writing only a piece of, it would be better to return an error code from the add_node() function rather than call exit. In some cases such as operating systems calling exit() can have direconsequences (shut down).
The C programming language was originally created to implement operating
systems and in some cases is still used for that purpose. While C doesn't have the exception throwing capabilities of C++, Java, C# and other more modern languages errors can be handled, either by returning error codes or using setjmp() and longjmp().
Code Snippets
typedef struct node{
int value;
struct node *next_ptr;
} Node;
Node *head;
void add_node(int data){
Node* temp = head;
/* ... */
}
void print_nodes(void){
Node* temp = head;
/* ... */
}case 'p':
/*+>*/ print_nodes(head); /* Pass by value */
break;
while(token != NULL){
node_value = strtol(token, &ptr, 10); /*Convert each string to integer*/
if((*ptr) != 10 && (*ptr) != 0){ /*If it's not a newline or a null then invalid input*/
fprintf(stderr, "Invalid number: %c", *ptr);
exit(EXIT_FAILURE);
}
/* ++> */ add_node(node_value, &head); /* Pass by reference */
token = strtok(NULL, s);
}
void add_node(int data, Node **head){
Node* temp;
if(*head == NULL){
*head = malloc(sizeof(struct node));
(*head)->value = data;
(*head)->next_ptr = NULL;
return;
}
temp = *head;
while(temp->next_ptr != NULL){
temp = temp->next_ptr;
}
if((temp->next_ptr = malloc(sizeof(struct node))) == NULL){
fprintf(stderr, "Out of memory");
exit(EXIT_FAILURE);
}
temp = temp->next_ptr;
temp->value = data;
temp->next_ptr = NULL;
}
void print_nodes(Node* head){
Node* temp = head;
if(temp == NULL){
printf("Linked list is empty\n");
}
for(temp = head; temp != NULL; temp = temp->next_ptr){
printf("%i\n", temp->value);
}
}add_node(node_value);long node_value;
void add_node(int data) { /* ... */add_node((int) node_value);Context
StackExchange Code Review Q#161499, answer score: 7
Revisions (0)
No revisions yet.