I have created 2 functions that read some data from a file and write the data in another file, but using linked lists and dynamically allocated strings in that list, but I have a logic error that I can't find:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct product {
char id[6];
char *name;
int price;
struct product *next;
};
struct product *read(struct product *head, FILE *input) {
struct product *p, *q, *aux;
p = (struct product *)malloc(sizeof(struct product));
char aux_id[6];
char aux_name[20];
int aux_price;
fscanf(input, "%s %s %d", aux_id, aux_name, &aux_price);
strcpy(p->id, aux_id);
p->name = (char *)malloc(strlen(aux_name) * (sizeof(char)));
strcpy(p->name,aux_name);
p->price = aux_price;
p->next = NULL;
head = p;
while (fscanf(input, "%s %s %d", aux_id, aux_name, &aux_price) != EOF) {
q = (struct product *)malloc(sizeof(struct product));
q->name = (char *)malloc(strlen(aux_name) * (sizeof(char)));
q->next = NULL;
strcpy(q->name, aux_name);
strcpy(q->id, aux_id);
q->price = aux_price;
p->next = q;
p = q;
}
return head;
}
void write(struct product *head, FILE *output) {
struct product *p;
p = head;
while (p != NULL) {
fprintf(output, "%s %s %d\n", p->id, p->name, p->price);
p = p->next;
}
}
int main() {
struct product *head, *p, *q;
FILE *input = fopen("input.txt", "r+");
FILE *output = fopen("output.txt", "w+");
head = read(head, input);
write(head, output);
fclose(input);
fclose(output);
}
input file looks like this:
333444 Cola 3
332312 Pepsi 4
123451 Mountain 3
output file looks like this
333444 Cola 3
332312°)q 4
123451à)q 3
There are multiple problems in your code:
the arrays into which you read the strings are too small: 6 bytes is not enough to store a 6 digit id, you need space for the null terminator. Same problem in the structure definition.
since you do not provide the maximum number of bytes to store into these arrays, fscanf()
stores the null terminator beynd the end of the aux_id
array, causing undefined behavior which explains the output.
the argument head
is unused in function read
and passed uninitialized in main()
.
You do not allocate enough space for the null terminator. You should either use:
p->name = malloc(strlen(aux_name) + 1);
strcpy(p->name, aux_name);
or simply:
p->name = strdup(aux_name);
read
and write
might cause problems as these names are used in the C library for system call wrappers."r"
and "w"
.fopen()
or malloc()
failures.Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct product {
char id[7];
char *name;
int price;
struct product *next;
};
struct product *read(FILE *input) {
struct product *head = NULL, *tail = NULL, *p;
char buf[100];
char aux_id[7];
char aux_name[20];
int aux_price;
while (fgets(buf, sizeof buf, input)) {
if (sscanf(buf, "%6s %19s %d", aux_id, aux_name, &aux_price) != 3) {
fprintf(stderr, "line format error: %s", buf);
continue;
}
p = (struct product *)malloc(sizeof(struct product));
if (p == NULL) {
fprintf(stderr, "memory allocation failure");
break
}
strcpy(p->id, aux_id);
p->name = strdup(aux_name);
if (p->name == NULL) {
fprintf(stderr, "memory allocation failure");
free(p);
break;
}
p->price = aux_price;
p->next = NULL;
if (head == NULL) {
head = p;
} else {
tail->next = p;
}
tail = p;
}
return head;
}
void write(struct product *head, FILE *output) {
struct product *p = head;
while (p != NULL) {
fprintf(output, "%s %s %d\n", p->id, p->name, p->price);
p = p->next;
}
}
int main() {
struct product *head;
FILE *input = fopen("input.txt", "r");
if (input == NULL) {
fprintf(stderr, "cannot open input file\n");
return 1;
}
FILE *output = fopen("output.txt", "w");
if (output == NULL) {
fprintf(stderr, "cannot open output file\n");
return 1;
}
head = read(head, input);
write(head, output);
fclose(input);
fclose(output);
return 0;
}
strdup()
is a POSIX function that is available on most systems and will be included in the next version of the C Standard. If your system does not have it, you can write it this way:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *s) {
size_t size = strlen(s) + 1;
char *p = malloc(size);
if (p == NULL)
return NULL;
return memcpy(p, s, size);
}