'How can I use strtok() and getline() to read the lines of a file into a linked list?
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char *name;
struct node *next;
};
typedef struct node LINK;
struct node *head;
head = NULL;
int main(int argv, char **argc){
// struct node *head, *current;
//open the file
int size;
//for the strtok()
const char space[1] = " ";
//char *name;
char *code;
//for the getline()
char *line;
line = (char *)malloc(size);
//number of characters in each line of file
int oneline;
FILE *fO;
fO = fopen("hw5.data", "r");
//check if file is not opening
if(fO == NULL){
printf("********************************************\n");
printf("You must include a filename to load.\n");
printf("********************************************\n");
}
//read the file data into the linked list
int x = 0;
while(getline(&line, &size, fO) != -1){
char *name = strtok(line, " ");
strtok(NULL, " ");
printf("Here is the name %s \n", name);
name = strtok(NULL, " ");
printf("here's the code for name %s\n", name);
x++;
free(name);
}
free(line);
//free(name);
return 0;
}
I need to use strtok() and getline() to read a file with a format of a name, 1 space and a single character per line like "Edward a" or "Bella d". This program returns:
Heres the name Edward
here's the code for name (null)
instead of "(null)" I was hoping it would return 'a'.
I have read the man page for strtok() and getline(); I am still confused about it. Does anyone know what the problem is? Sorry, I'm just required to use strtok() and getline().
Here is the function I was talking about actually, I was trying to sort the linked list of strings with the strcmp(), to accordingly place the new string into the linked list. If the LinkedList was empty then Edward could be added. Otherwise, I tried to compare the input char name[] to the existing strings to put it in its place in ascending order.
//function to search list
int LIST_SEARCH(char name[], LINK *head) {
LINK *current;
current = head;
while (current != NULL) {
if (!strcmp(current->name, name)){
current = current->next;
printf(" here it is 1.\n");
printf("\n");
return 1;
}
}
printf("Did not find it.\n");
printf("\n");
return 0;
}
LINK *LIST_INSERT(char name[], LINK *head) {
LINK *current, *temp1;
if (LIST_SEARCH(name, head) == 1){
return head;
}
temp1 = (LINK *)malloc(sizeof(LINK));
strcpy(temp1->name, name);
//test if the list is empty.
if (head == NULL) {
printf("empty\n");
head = temp1;
temp1->next = NULL;
return head;
}
//add the string to front of the list
current = head;
if(strcmp(current->name, name) > 0){
printf("add name to front: %s\n", name);
temp1->next = current;
head = temp1;
return head;
}
//put the string at the back or middle of list
current = head;
while (current != NULL) {
if (current->next == NULL || strcmp(current->next->name, name) > 0){
printf("add name elsewhere: %s\n", name);
temp1->next = current->next;
current->next = temp1;
return head;
}
//iterate
current = current->next;
}
}
The function seemed to have added the first name. However, for the rest of the names, it does not execute the print statements and the program does not finish. It does not give errors either.
Solution 1:[1]
You have the code:
char *name = strtok(line, " ");
strtok(NULL, " ");
You can't afford to discard the result of the second call to strtok() like that — it contains the pointer to the code. Remove that line!
There are other problems too. You don't initialize size; it should be of type size_t anyway. You have unused extraneous code in the question too. You check whether the file was opened (though the message is a bit odd); that's good. However, you continue to use the unopened file; that's bad. You should report the error on standard error, not standard output. It would be good to include the file name in the message. It would be a good idea to zap the newline after reading the line. You should not call free(name). The space allocated by getline() is pointed at by line, and you should (and do) call free(line) when the input loop completes. The value returned by strtok() should not be freed; it does not allocate space, and the pointer returned is not guaranteed to the pointer returned by malloc().
Here's working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
size_t size = 0;
char *line = 0;
const char *filename = "hw5.data";
FILE *fO = fopen(filename, "r");
if (fO == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", filename);
exit(EXIT_FAILURE);
}
while (getline(&line, &size, fO) != -1)
{
line[strcspn(line, "\n\r")] = '\0';
char *name = strtok(line, " ");
char *code = strtok(NULL, " ");
printf("Here is the name '%s'\n", name);
printf("here's the code for name '%s'\n", code);
}
free(line);
return 0;
}
For the described input, it yields:
Here is the name 'Edward'
here's the code for name 'a'
Here is the name 'Bella'
here's the code for name 'd'
Note that when you get around to adding the data to your linked list, you'll need to duplicate the strings found — use strdup().
Here is some code which creates, prints and releases a linked list using strdup() to copy the name. Since the structure in the question has no place for storing the code, the code is printed while reading the data but otherwise ignored. Note that I renamed the structure tag to Node, and used the tag as the typedef name too. Also, note that there are no global (file scope) variables; you should avoid them as often as possible, which is most of the time.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node Node;
struct Node
{
char *name;
Node *next;
};
static Node *new_node(Node *head, const char *name)
{
Node *np = malloc(sizeof(*np));
if (np == NULL)
{
fprintf(stderr, "Failed to allocate %zu bytes of memory\n", sizeof(*np));
exit(EXIT_FAILURE);
}
np->name = strdup(name);
if (np->name == NULL)
{
fprintf(stderr, "Failed to allocate %zu bytes of memory\n", strlen(name) + 1);
exit(EXIT_FAILURE);
}
np->next = head;
return np;
}
static void print_list(const Node *head)
{
const Node *curr = head;
size_t count = 0;
while (curr != NULL)
{
printf("%zu: [%s]\n", ++count, curr->name);
curr = curr->next;
}
}
static void free_list(Node *head)
{
Node *curr = head;
while (curr != NULL)
{
Node *next = curr->next;
free(curr->name);
free(curr);
curr = next;
}
}
int main(void)
{
const char *filename = "hw5.data";
FILE *fO = fopen(filename, "r");
if (fO == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", filename);
exit(EXIT_FAILURE);
}
Node *head = NULL;
size_t size = 0;
char *line = NULL;
while (getline(&line, &size, fO) != -1)
{
line[strcspn(line, "\n\r")] = '\0';
char *name = strtok(line, " ");
char *code = strtok(NULL, " ");
printf("Here is the name '%s'\n", name);
printf("Here is the code '%s'\n", code);
head = new_node(head, name);
}
free(line);
print_list(head);
free_list(head);
return 0;
}
I used this as the data file hw5.data:
Edward a
Bella d
Jacob a
Renesmee b
Jasper c
Rosalie b
Alice a
Carlisle a
The output from the program is then:
Here is the name 'Edward'
Here is the code 'a'
Here is the name 'Bella'
Here is the code 'd'
Here is the name 'Jacob'
Here is the code 'a'
Here is the name 'Renesmee'
Here is the code 'b'
Here is the name 'Jasper'
Here is the code 'c'
Here is the name 'Rosalie'
Here is the code 'b'
Here is the name 'Alice'
Here is the code 'a'
Here is the name 'Carlisle'
Here is the code 'a'
1: [Carlisle]
2: [Alice]
3: [Rosalie]
4: [Jasper]
5: [Renesmee]
6: [Jacob]
7: [Bella]
8: [Edward]
I use quotes and square brackets around the names to demonstrate that there are no extraneous characters.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
