I am reading from a file. The file has following contents:
One Fish Two 2 Red 2 Blue 2
Dr. Seuss
7 fish, 8 2, 8 2, 8 2,
Black 2, 3 2, Old 2, New 2.
This one has a little car.
6 6 6 6 6 star.
Say! What 5 lot of 12 there are.
Yes. Some 3 red, and some 4 blue.
6 3 old 6 6 4 new.
6 3 sad, 6 6 4 glad,
And 4 4 very, 1 bad.
Why 4 they 10 10 10 2 7?
0
I am parsing file and printing like exactly it is at the moment. The dtok.c file that contains the function for parsing strings and have dlmfnt
and dlmbck
return values.
dtok.c:
#include <string.h>
#include <malloc.h>
#include <assert.h>
char *dtok_r(char *s, const char *delim, char **save_ptr, char **dlmfnt, char *dlmbck) {
*dlmfnt = NULL;
*dlmbck = '\0';
char *end;
if (s == NULL)
s = *save_ptr;
if (*s == '\0') {
*save_ptr = s;
return NULL;
}
/* Scan the length of leading delimiter str. */
size_t dlmfnt_len = strspn(s, delim);
if (dlmfnt_len > 0) {
*dlmfnt = (char *)malloc((dlmfnt_len 1) * sizeof(char));
assert(dlmfnt != NULL && "NOT ENOUGH MEMORY FOR dlmfnt!!!");
strncpy(*dlmfnt, s, dlmfnt_len);
*(dlmfnt)[dlmfnt_len] = '\0';
}
s = dlmfnt_len;
if (*s == '\0') {
*save_ptr = s;
return NULL;
}
/* Find the end of the token. */
end = s strcspn(s, delim);
if (*end == '\0') {
*save_ptr = end;
return s;
}
/* Terminate the token and make *SAVE_PTR point past it and assign dlmbck */
if (*end != '\n') {
*dlmbck = *end;
}
*end = '\0';
*save_ptr = end 1;
return s;
}
This is my main.c which is reading from file and parsing it and printing it:
/* Include standard library headers */
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>
#include <assert.h>
#include <stddef.h>
/* System Constants */
#define MAX_LINE_SIZE 512
int main(int argc, char **argv) {
assert(argc == 2 && \
"Program only operates with one file"
);
/* Open the file to decompress */
FILE *dcomp_file = fopen(argv[1], "r");
assert(dcomp_file != NULL && \
"Error opening file -->possibly missing<--"
);
/* Line Buffer for fgets */
char line_buff[MAX_LINE_SIZE];
/* dtok_r variable inits */
char *word_token, *save_ptr, dlmbck;
static const char *delim = " \n,.?!'\":;-"; /* Delimiter string for dtok_r */
/* Read line from file until end of file */
while (((fgets(line_buff, MAX_LINE_SIZE, dcomp_file) != NULL) && \
(strcmp(line_buff, "0\n") != 0))) {
save_ptr = line_buff;
if (strcmp(line_buff, "\n") != 0) {
char *dlmfnt = NULL;
while ((word_token = dtok_r(save_ptr, delim, &save_ptr, &dlmfnt, &dlmbck))) {
if (dlmfnt != NULL) {
printf("%s", dlmfnt);
//free(dlmfnt);
}
printf("%s", word_token);
putchar(dlmbck);
}
putchar('\n');
}
}
/* Close the decomp file */
int fclose_res = fclose(dcomp_file);
assert(fclose_res == 0);
/* Stop screen from disappearing until any character is pressed */
getchar();
return EXIT_SUCCESS;
}
What happens here is when I uncomment free(dlmfnt)
, I get wrong outputs. but I do not free the array I do not get the wrong output.
Correct Output which I get when I do not use free
One Fish Two 2 Red 2 Blue 2
Dr. Seuss
7 fish, 8 2, 8 2, 8 2,
Black 2, 3 2, Old 2, New 2.
This one has a little car.
6 6 6 6 6 star.
Say! What 5 lot of 12 there are.
Yes. Some 3 red, and some 4 blue.
6 3 old 6 6 4 new.
6 3 sad, 6 6 4 glad,
And 4 4 very, 1 bad.
Why 4 they 10 10 10 2 7?
When I use free the output I get:
One Fish Two 2 Red 2 Blue 2
Dr. Seuss
7 fish, -d8 2, -d8 2, -d8 2,
Black 2, 3 2, -dOld 2, -dNew 2.
This one has a little car.
6 6 6 6 6 star.
Say! What 5 lot of 12 there are.
Yes. Some 3 red, -dand some 4 blue.
6 3 old 6 6 4 new.
6 3 sad, 6 6 4 glad,
And 4 4 very, 1 bad.
Why this happening how can I solve it?
CodePudding user response:
There are some issues in your code:
the assertion
assert(dlmfnt != NULL && "NOT ENOUGH MEMORY FOR dlmfnt!!!")
is incorrect: you do not check for memory allocation failure, but just ifdlmfmt
is not null. Useassert(*dlmfnt != NULL ...
*(dlmfnt)[dlmfnt_len] = '\0'
is parsed as*(dlmfnt[dlmfnt_len]) = '\0'
, which has undefined behavior ifdlmfnt_len
is non zero, potentially corrupting memory, causing the observed behavior. You might want so simply the code usingstrndup()
:if (dlmfnt_len > 0) { *dlmfnt = strndup(s, dlmfnt_len); assert(*dlmfnt != NULL && "NOT ENOUGH MEMORY FOR dlmfnt!!!"); }
when you use
putchar(dlmbck)
after the last word, you output a null byte, which may not appear on the terminal, but would be stored if output is redirected to a file. You should test:if (dlmbck) { putchar(dlmbck); }