determine content-length and append '\0'
fseek(fp, 0, SEEK_END);
long fp_len;
fp_len = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *text = malloc(sizeof(*text) * fp_len + 1);
size_t len = fread(text, fp_len, 1, fp);
text[fp_len] = '\0';
fp_len prints : 400, while len prints : 1
printf("%d", fp_len);
printf("%d", len);
my understanding is this is wrong:
text[fp_len] = '\0';
and this is correct :
text[len] = '\0';
but if "len" is printing 1..
wouldn't '\0' be added to the 2nd spot in the array ?
Call fread(text, fp_len, 1, fp) asks to read one element of size fp_len so after succesful execution result is 1 (number of elements read) or it can be 0 if reading fails.
If you want to count number of bytes (character) read from file, you can change places of arguments, like
fread(text, 1, fp_len, fp)
For more information refer to references
size_t fread(void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream);
As other have said, fread returned 1 - the number of elements read and each had a size of size or 400.
Put the augments in the correct order.
// size_t len = fread(text, fp_len, 1, fp);
size_t len = fread(text, 1, fp_len, fp);
Better to avoid magic numbers like 1 here. Instead, use the size of the text[] element.
size_t len = fread(text, sizeof *text, fp_len, fp);
Further, code lacks error checking and printf() specifier correctness.
if (fp == NULL) Handle_Error("fopen");
if (fseek(fp, 0, SEEK_END)) Handle_Error("fseek");
long fp_len = ftell(fp);
if (fp_len == -1) Handle_Error("ftell");
if (fp_len < 0 || fp_len >= SIZE_MAX) Handle_Error("long to size_t");
char *text = malloc(sizeof *text * (fp_len + 1));
if (text == NULL) Handle_Error("malloc");
size_t len = fread(text, 1, fp_len, fp);
if (len == 0 && fp_len > 0) Handle_Error("fread");
text[len] = '\0';
printf("%ld", fp_len); // note specifiers
printf("%zu", len);
According to the manual page you need to write
fread(text, 1, fp_len, fp);
Related
I am reading a file using a small buffer and printing it. But after every time it after fread and printf some unrecognized characters appear. I do not know why.
I think it has something to do with printf and not fread.
This is the small code:
f = fopen(host_filename2, "r");
char chunks[4];
int size;
do {
memset(chunks,0,sizeof chunks);
size = fread(chunks, 1, sizeof chunks, f);
if (size <= 0) break;
printf("%s", chunks);
} while (size == sizeof chunks);
fclose(f);
printf("%s", chunks); expect chunks[] to be a string. Strings have a null character at the end and fread(chunks, 1, sizeof chunks, f) did not certainly read a '\0' and form a string.
Write what was read (Best)
// printf("%s", chunks);
fwrite(chunks, 1, size, stdout);
Write what was read up to a '\0'
"%.*s" writes a limited amount from a character array, stopping at the size or when a '\0' is detected.
// printf("%s", chunks);
printf("%.*s", size, chunks);
Append your own '\0'
This will perform like printf("%.*s", size, chunks).
char chunks[4 + 1]; // One bigger
int size;
do {
// memset(chunks,0,sizeof chunks - 1); // Not needed
size = fread(chunks, 1, sizeof chunks - 1, f);
if (size <= 0) break;
chunks[size] = '\0';
printf("%s", chunks);
} while (size == sizeof chunks - 1);
Avoid naked magic numbers
Use size_t for array sizing.
#define CHUNK_SIZE 4
char chunks[CHUNK_SIZE];
size_t size;
size_t n = sizeof chunks/sizeof *chunks;
do {
size = fread(chunks, sizeof *chunks, n, f);
if (size <= 0) break;
fwrite(chunks, sizeof *chunks, size, stdout);
} while (size == sizeof chunks);
I call a method with:
char * buffer = read_string_from_file();
Here is the method:
char * read_string_from_file() {
char * filename = "C:/Users/xxxxx/Dropbox/c-programming-test-file.txt"; // later I will give this as a parameter
char * buffer = 0;
long file_length;
FILE * file = fopen (filename, "r");
if (file)
{
fseek (file, 0, SEEK_END);
file_length = ftell (file);
fseek (file, 0, SEEK_SET);
buffer = malloc (file_length);
if (buffer)
{
fread (buffer, 1, file_length, file);
}
fclose (file);
return buffer;
}
}
The file contains:
2461866 -3134537
When printing the buffer with printf("buffer: %s\n\n", buffer); I get buffer: 2461866 -3134537Files\Jey┘·å¬. Instead I expected: buffer: 2461866 -3134537. How do I adjust the size of the char array buffer?
With printf("buffer: %s\n\n", buffer);, "%s" needs buffer to point to a string. In OP's case, it is not, thus UB (extra junk printed).
If the length can be known, simply print with fwrite()
fwrite(buffer, 1, file_length, stdout);
or as buffer is not certainly a string, code could use the following if file_length < INTMAX.
printf("%.*s", (int) file_length, buffer);
or change read_string_from_file() to form a string. Append a null character.
// buffer = malloc (file_length);
buffer = malloc (file_length + 1);
if (buffer) {
fread (buffer, 1, file_length, file);
// add
buffer[file_length] = '\0';
...
printf("buffer: %s\n", buffer);
Without a null character, buffer is not a string.
Aside: Robust code would check the results of ftell(), fread() too.
In C strings must be NUL terminated.
You can do this for example:
...
buffer = malloc (file_length + 1); // + 1 for the NUL terminator
buffer[file_length] = 0; // put NUL terminator
...
I want to read lines from stdin with variable length until the end of input. The example input would be something like this:
#.###############
#...#...........#
#.###.#####.#.###
#...........#...#
###############.#
but with various lengths of rows and columns.
What is the best way to read it into 2d array except for reading it as chars?
Assuming you're running on a POSIX-compliant system, you can use the getline() function to read lines of almost arbitrary length (only limited by available memory). Something like this should work:
char *line = NULL;
size_t bytes = 0UL;
for ( int ii = 0;; ii++ )
{
ssize_t bytesRead = getline( &line, &bytes, stdin );
if ( bytesRead <= 0L )
{
break;
}
lineArray[ ii ] = strdup( line );
}
free( line );
You'll have to add error checking and take care of lineArray yourself.
char *buff = malloc(1024 * 100); // 100K should be plenty, tweak as desired.
char *maze = 0;
int width = 0,
int height = 0;
FILE *fp = fopen(input.txt, "r");
fgets(buff, 1024 * 100, fp);
if(!strchr(buff, '\n'))
goto failed_sanity_test;
striptrailingwhitespace(buff);
if(height == 0)
width = strlen(buff);
/* sanity-test width ? */
else
if(strlen(buff) != width)
goto ragged_edge_maze;
temp = realloc(maze, width * (height + 1));
if(!temp)
goto out_of_memory;
maze = temp;
memcpy(maze + height * width, buff, width);
height++;
Its fiddly in C in comparison to many other langues, but at least you have full control of the error conditions.
This question already has answers here:
C Concatenate string in while loop
(2 answers)
Closed 6 years ago.
I cant seem to use the following function to concatenate a string in the while loop. Any idea what Im doing wrong?
void do_file(FILE *in, FILE *out, OPTIONS *options)
{
char ch;
int loop = 0;
int sz1,sz2,sz3;
int seeker = offsetof(struct myStruct, contents.datas);
//find total length of file
fseek(in, 0L, SEEK_END);
sz1 = ftell(in);
//find length to struct beginning and minus that from total length
fseek(in, seeker, SEEK_SET);
sz2 = sz1 - ftell(in);
sz3 = (sz2 + 1) * 2;//Allocate enough size for 2x array length
char buffer[sz3];//set size of buffer to be copied to
char msg[sz3];//set size of msg
buffer[0] = '\0';
while (loop < sz2)
{
if (loop == sz2)
{
break;
}
fread(&ch, 1, 1, in);
//sprintf(msg, "%02X", (ch & 0x00FF));
strcat(buffer, msg);
++loop;
}
printf("%s\n", buffer);
}
Your only strcat appends the char msg[sz3]; which is never filled.
EDIT
The simplest fix would be to add
msg[1] = '\0';
after
char msg[sz3];//set size of msg
and to replace
fread(&ch, 1, 1, in);
with
fread(&msg[0], 1, 1, in);
I wish to get strings from the buffer of raw bytes in the memory, will work well?
static int in = 0;
void *loadFile (FILE *fp)
{
fseek (fp, 0L, SEEK_END);
size_t size = ftell (fp);
fseek (fp, 0L, SEEK_SET);
char *buf = malloc (sizeof(char) * size);
if (!buf)
return NULL;
if (fread (buf, sizeof(char), size, fp) != size) {
free (buf);
return NULL;
}
return buf;
}
char *getString (void *buf)
{
char *l_buf = buf;
int i, j, num;
char *string = NULL;
for (i = in; l_buf[i] == '\n' || l_buf[i] == '\r'; i++);
for (j = i; l_buf[j] != '\n' && l_buf[j] != '\r'; j++);
num = j - i;
string = malloc (sizeof(char) * (num + 1));
if (!string)
return NULL;
in = j;
strncpy (string, &l_buf[i], num);
string[num] = '\0';
return string;
}
I believe there is at least one problem with the solution as proposed and that is there is no check to ensure you don't run off the end of the memory buffer in getString(). So one way to avoid this in your read code would be to add an explicit NULL to the end of the buffer like so
char *buf = malloc (sizeof(char) * (size + 1));
if (!buf)
return NULL;
if (fread (buf, sizeof(char), size, fp) != size) {
free (buf);
return NULL;
}
buf[size] = `\0`;
And then in your string extraction function add the a NULL check to the line termination tests, something like this:
for (i = in; l_buf[i] != '\0' && (l_buf[i] == '\n' || l_buf[i] == '\r'); i++);
if (l_buf[i] == '\0') {
/* Never saw the start of a line before the buffer ran out */
return NULL;
}
for (j = i; l_buf[i] != '\0' && l_buf[j] != '\n' && l_buf[j] != '\r'; j++);
if (i == j) {
return NULL;
}
There is another potential problem but as you didn't say whether you were running on UNIX or Windows or cared about portability here I can't be sure. The proposed code doesn't deal with line terminations that include both `\r' and '\n'.
I would also suggest to make the function re-entrant by replacing the global start position index with a parameter like so:
char *getString (void *buf, int *in) { ...
Then just update that pointer in getString() like so:
*in = j;
All references to buf[i] should be l_buf[i]. buf[i] is indexing from a void pointer (not what you want), but l_buf [i] is indexing from a char pointer.