Itay Lavi
Itay Lavi

Reputation: 13

Weird characters while getting str from a file in C

I tried to get the file's content and put it into a string. When I run my program and I print the string I get the file's content with some weird characters afterward.

My code:

int size = 0;
char ch = 0;
char* content = 0;
FILE* fs = fopen(file, "r");
//getting file's content and put it into a string
while (ch != EOF)
{
    ch = (char)fgetc(fs);
    size++;
    content = myRealloc(content, size);
    content[size - 1] = ch;
} 
printf("%s", content);

myRealloc:

char* myRealloc(char* array, int size)
{
    char* temp = 0;
    temp = realloc(array, size * sizeof(char));
    return temp;
}

The file's content:

1,2,3,4
5,6,7,8
a,b,c,d
e,f,g,h

When I print:

1,2,3,4
5,6,7,8
a,b,c,d
e,f,g,h ²²²²ר─

Upvotes: 0

Views: 2779

Answers (4)

user3629249
user3629249

Reputation: 16530

regarding:

printf("%s", content);

the code that filled in the contents of content failed to NUL terminate that array of characters.

(and the allocated memory doesn't have enough room to append a NUL char)

so the call to printf() will keep outputting characters until it finds a NUL char.

That is the underlying reason for the junk characters being output.

Upvotes: 0

Moshe Gottlieb
Moshe Gottlieb

Reputation: 4003

Your string is not null terminated. You need to allocate enough space to hold the last null character, something like temp = realloc(array, (size + 1) * sizeof(char)); and at the end do something like content[size] = '\0'. However, using realloc is probably the worst way to do what you're trying to do.

I'd use stat to find the file's size, then use mmap to map the file to memory and then malloc to the size of the file, and then memcpy to the malloced memory. realloc is evil, performance wise.

Here is an alternative that greatly outperforms the original code:

#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char** argv){
    if (argc != 2){
      printf("Usage: %s {filename}\n",argv[0]);
      return 1;
    }
    int fd = open(argv[1], O_RDONLY);
    // @todo: check if fd is valid
    struct stat st;
    int ret = fstat(fd,&st);
    // @todo: check ret
    void* mapped_memory = mmap(NULL,st.st_size,PROT_READ,MAP_SHARED,fd,0);
    // @todo: check mapped_memory that is not null
    char* str = (char*)malloc(sizeof(char)*(st.st_size + 1));
    // @todo: check that str is not null
    memcpy(str,mapped_memory,st.st_size);
    str[st.st_size] = '\0';
    printf("%s",str);
    free(str);
    munmap(mapped_memory,st.st_size);
    close(fd);
    return 0;
}

Upvotes: 1

Achal
Achal

Reputation: 11921

The statement ch = (char)fgetc(fs); in the loop also try to print EOF, which you shouldn't.

Just Replace that block of code with

while ( (ch = fgetc(fs)) != EOF) { /* fetch the char & check the condition */
      putchar(ch);
      size++;
      content = myRealloc(content, size);
      content[size - 1] = ch;
}
size++;
content = myRealloc(content, size);
content[size - 1] = '\0';
print("%s", content);

Also check the manual page of fgetc() it returns int. So make ch type as int.

 int fgetc(FILE *stream);

Also print("%s", content); should be printf("%s", content); unless you didn't define print().

Finally & most importantly once job is done, don't forgot to free the dynamically allocated memory by calling free() function.

Upvotes: 1

Jeremy Pare
Jeremy Pare

Reputation: 177

Add the null terminated character at the end:

int size = 0;
int ch = 0;
char* content = 0;
FILE* fs = fopen(file, "r");
//getting file's content and put it into a string
while ((ch = fgetc(fs)) != EOF)
{
    size++;
    content = myRealloc(content, size);
    content[size - 1] = (char)ch;
}
size++;
content = myRealloc(content, size);
content[size - 1] = '\0';
print("%s", content);

Edit: Also, as pointed out by @achal, you are trying to add the EOF character since when you read it you are already in the while loop. I modified my code accordingly.

Upvotes: 4

Related Questions