RLE algorithm should compress bytes in c - c

I know there are too many questions about this algorithm but I couldn't really find a good answer for compressing the bytes. I am kind of a newbie in C. I have the following code:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
//compress function here...
int main(int argc, char **argv) {
if(argc != 2){
fprintf(stderr, "Wrong argument number\n");
exit(1);
}
FILE *source = fopen(argv[1], "rb");
if(source == NULL){
fprintf(stderr, "Cannot open the file to be read\n");
exit(1);
}
FILE *destination;
char name = printf("%s.rle", argv[1]);
while((destination = fopen(&name, "wb")) == NULL){
fprintf(stderr, "Can't create the file to be written\n");
exit(1);
}
compress_file(source, destination);
int error;
error = fclose(source);
if(error != 0){
fprintf(stderr, "Error: fclose failed for source file\n");
}
error = fclose(destination);
if(error != 0){
fprintf(stderr, "Error: fclose failed for destination file\n");
}
}
If this is test.c and the executable is test. I need to make this work on terminal/command prompt as "./test file.txt". My file.txt includes something like (bytes):
20 21 20 20 8F 8F 21 21 64 60 70 20 21 90 90
and the desired output is:
01 20 01 21 02 20 02 8F 02 21 01 64 01 60 01 70 01 20 01 21 02 90
My code create a file and that file includes:
0b00 0000 0106 0000 0000 0000 0000 0000
0000 0000 0a
instead what I want. What do I miss?
Also I want my file to be named as file.txt.rle but it has no name.
EDIT:
char name[30];
sprintf(name, "%s.rle", argv[1]);
solved the problem for naming.

Also I want my file to be named as file.txt.rle but it has no name.
Well, this code
char name = printf("%s.rle", argv[1]);
while((destination = fopen(&name, "wb")) == NULL){
doesn't give you a string like "file.txt.rle". Instead try something like:
size_t len = strlen(argv[1]) + 4 + 1;
char name[len];
sprintf(name, "%s.rle", argv[1]);
while((destination = fopen(name, "wb")) == NULL){
instead what I want. What do I miss?
Well, you miss that you need to put data into str
This code
char str[BUF_SIZE];
fwrite(str, sizeof(str), 1, destination);
just writes an uninitialized variable to the file.
I'll not give you a complete solution but here is something that you can start with and then figure the rest out yourself.
void compress_file(FILE *source, FILE *destination){
char str[BUF_SIZE];
int index = 0;
int repeat_count = 0;
int previous_character = EOF;
int current_character;
while((current_character = fgetc(source)) != EOF){
if(current_character != previous_character) {
if (previous_character != EOF) {
// Save the values to str
str[index++] = repeat_count;
str[index++] = previous_character;
}
previous_character = current_character;
repeat_count = 1;
}
else{
repeat_count++;
}
}
if (repeat_count != 0)
{
str[index++] = repeat_count;
str[index++] = previous_character;
}
fwrite(str, index, 1, destination);
}
EXAMPLE 1:
Let's say a file.txt is:
ABBCCC
On linux it can be displayed hexadecimal like this:
# hexdump -C file.txt
00000000 41 42 42 43 43 43 |ABBCCC|
After running the program, you have:
hexdump -C file.txt.rle
00000000 01 41 02 42 03 43 |.A.B.C|
EXAMPLE 2:
Let's say that file.txt is like
# hexdump -C file.txt
00000000 20 21 20 20 8f 8f 21 21 64 60 70 20 21 90 90 | ! ..!!d`p !..|
the result will be
# hexdump -C file.txt.rle
00000000 01 20 01 21 02 20 02 8f 02 21 01 64 01 60 01 70 |. .!. ...!.d.`.p|
00000010 01 20 01 21 02 90 |. .!..|

As pointed in comments, you have two problems:
Usage of printf instead of sprintf,
Writting to file what you've counted.
Name Creation
char name = printf("%s.rle", argv[1]);
destination = fopen(&name, "wb");
The first line will store the number of characters in argv[1] plus 4 into name. Since, from man printf:
Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings).
The second line is more problematic : you ask fopen to open a file giving it a pointer to char instead of a read string.
One correct way to do what you want is:
/* reserve memory to store file name
NOTE: 256 here might not large enough*/
char name[256];
/* fill name array with original name + '.rle'
The return of sprintf is tested to assert that its size was enough */
if (snprintf(name, sizeof name, "%s.rle", argv[1]) >= sizeof name)
{
fprintf(stderr, "name variable is not big enough to store destination filename");
}
Writting to file
The code
char str[BUF_SIZE];
fwrite(str, sizeof(str), 1, destination);
reserve a big array, and writes it to file, without initializing it. To do what you want, you can have this approach:
make a function that will only write two characters in file: the number of character found and the character itself
call this function each time needed (at character changing, but not when one of character is EOF...)
Let's look at :
void write_char_to_file(FILE *f, int count, char car)
{
/* char array to be stored in file */
char str[2];
/* number of repeating characters */
str[0] = count;
/* the character */
str[1] = car;
/* write it to file */
fwrite(str, sizeof str, 1, f);
}
This function has two potential problems:
It doesn't handle char overflow (what if count is over 256?),
It doesn't test the return of fwrite.
Then, when this function should be called, when the current character changes:
EOF A A B C C EOF
In this example, we have 4 characters changes, but we want only 3 writting in the file, so:
Character changing when previous is EOF must be ignored (else we would write something like 0 (char)EOF at file starting),
One writting must be added after while loop since, when the last reading gives EOF, we still have 2 C to write to file.
Let's look at the code:
while((current_character = fgetc(source)) != EOF) {
if(current_character != previous_character) {
/* ignore initial change */
if (previous_character != EOF) {
write_char_to_file(destination, repeat_count, previous_character);
}
previous_character = current_character;
repeat_count = 1;
} else {
repeat_count++;
}
}
/* write last change */
write_char_to_file(destination, repeat_count, previous_character);
This code have a problem too: what if the input file is empty? (first read gives EOF)
The complete code:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define BUF_SIZE 5096
void write_char_to_file(FILE *f, int count, char car)
{
/* char array to be stored in file */
char str[2];
/* number of repeating characters */
str[0] = count;
/* the character */
str[1] = car;
/* write it to file */
fwrite(str, sizeof str, 1, f);
}
void compress_file(FILE *source, FILE *destination)
{
int repeat_count = 0;
int previous_character = EOF;
int current_character;
while((current_character = fgetc(source)) != EOF) {
if(current_character != previous_character) {
if (previous_character != EOF) {
write_char_to_file(destination, repeat_count, previous_character);
}
previous_character = current_character;
repeat_count = 1;
} else {
repeat_count++;
}
}
write_char_to_file(destination, repeat_count, previous_character);
}
int main(int argc, char **argv) {
if(argc != 2) {
fprintf(stderr, "Wrong argument number\n");
exit(1);
}
FILE *source = fopen(argv[1], "rb");
if(source == NULL) {
fprintf(stderr, "Cannot open the file to be read\n");
exit(1);
}
FILE *destination;
/* reserve memory to store file name
NOTE: 256 here might not large enough*/
char name[256];
/* fill name array with original name + '.rle'
The return of sprintf is tested to assert that its size was enough */
if (snprintf(name, sizeof name, "%s.rle", argv[1]) >= sizeof name)
{
fprintf(stderr, "name variable is not big enough to store destination filename");
}
/* while is not needed here, if do the job */
if((destination = fopen(name, "wb")) == NULL) {
fprintf(stderr, "Can't create the file to be written\n");
exit(1);
}
compress_file(source, destination);
int error;
error = fclose(source);
if(error != 0) {
fprintf(stderr, "Error: fclose failed for source file\n");
}
error = fclose(destination);
if(error != 0) {
fprintf(stderr, "Error: fclose failed for destination file\n");
}
/* main must return a integer */
return 0;
}

Related

Read PNG file with c

I want to read a PNG image file with C without any library. From PNG (Portable Network Graphics) Specification Version 1.0 any PNG file has a signature that distinguishes it from other image formats. The signature is the first 8 bytes of the image.
Some sources like the above RFC mentioned the signature as:
137 80 78 71 13 10 26 10 (decimal)
Or like Not able to read IHDR chunk of a PNG file mentioned the signature as:
89 50 4E 47 0D 0A 1A 0A (ASCii)
So, I write a simple code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE (8)
int main(int argc, char **argv){
if(argc != 2) {
printf("Usage: %s <png file>\n", argv[0]);
return 1;
}
char *buf = (char *)malloc(MAX_SIZE);
if(!buf) {
fprintf(stderr, "Couldn't allocate memory\n");
return 1;
}
FILE *f = fopen(argv[1], "r");
if(!f) {
perror("fopen");
printf("Invalid file\n");
free(buf);
return 1;
}
int size = fread(buf, 1, MAX_SIZE, f);
printf(%c\n", buf[1]);
printf(%c\n", buf[2]);
printf(%c\n", buf[3]);
printf(%c\n", buf[4]);
printf(%c\n", buf[5]);
printf(%c\n", buf[6]);
printf(%c\n", buf[7]);
printf(%c\n", buf[8]);
fclose(f);
free(buf);
system("pause");
return 0;
}
When I print the bytes by printf, the output is not like the above.
This is what it shows:
ëPNG→►v#,
Can someone describe what happened and what can I do to modify it?
You need to print each value with the correct format specifier. Here we want numerical representations, not character ones.
From the documentation on printf:
%c writes a single character
%d converts a signed integer into decimal representation
%x converts an unsigned integer into hexadecimal representation
%02X prints a hexadecimal with a minimum width of two characters, padding with leading zeroes, using ABCDEF (instead of abcdef).
See also implicit conversions.
An example:
#include <stdio.h>
#define SIZE 8
int main(int argc, char **argv) {
unsigned char magic[SIZE];
FILE *file = fopen(argv[1], "rb");
if (!file || fread(magic, 1, SIZE, file) != SIZE) {
fprintf(stderr, "Failure to read file magic.\n");
return 1;
}
/* Decimal */
for (size_t i = 0; i < SIZE; i++)
printf("%d ", magic[i]);
printf("\n");
/* Hexadecimal */
for (size_t i = 0; i < SIZE; i++)
printf("%02X ", magic[i]);
printf("\n");
fclose(file);
}
Output:
137 80 78 71 13 10 26 10
89 50 4E 47 0D 0A 1A 0A

Reading a line from a file and storing it in variables

I've got a file with 2-3 lines, and every line I want to store in a char* variable, then translate it and store it to other appropriate variables.
not in unix, just in c, there's a fscanf(%d,%s,%s, 1,2,3); and thats it, but in unix it is somewhat weird.
For example: a abc 12 12
Storing it in char msg[20], and then msg[20] will be stored in 4 variables, one char, one char* and two integers. How can It be done?
Here what I got so far:
int ret_in, in1,file;
char buffer1[BUF_SIZE];
int i =0;
char fn[5] = "file";
char msg[20];
file = open(fn,O_WRONLY|O_CREAT,0644);
//msg = "test";
while(((ret_in = read (file, &buffer1, BUF_SIZE)) > 0))
{
for(i; i<ret_in; i++)
{
if(buffer1[i]!='\n')
msg[i] = buffer1[i];
}
}
printf("%s", msg); //TEST: check msg
close(file);
It stores it fine in the msg variable, but if it composed of 4 'items' i want to store in different variables, how can I do it efficiently?
You can use fopen() to open a file and get a pointer to a file stream. This pointer can be passed to fgets() to retrieve lines from the file and store them in a buffer. This buffer can then be parsed by using sscanf().
Here is an example of how this might work. Note that here I am using arrays to store the components of the fields from each line; you may have different requirements.
#include <stdio.h>
#include <stdlib.h>
#define MAX_LINES 100
int main(void)
{
FILE *fp = fopen("my_file.txt", "r");
if (fp == NULL) {
perror("Unable to open file");
exit(EXIT_FAILURE);
}
char buffer[1000];
char id[MAX_LINES];
char msg[MAX_LINES][10];
int val_a[MAX_LINES];
int val_b[MAX_LINES];
size_t lines = 0;
while (fgets(buffer, sizeof buffer, fp) != NULL) {
if (sscanf(buffer, "%c%9s%d%d",
&id[lines], msg[lines], &val_a[lines], &val_b[lines]) == 4) {
++lines;
}
}
for (size_t i = 0; i < lines; i++) {
printf("Line %zu: %c -- %s -- %d -- %d\n",
i+1, id[i], msg[i], val_a[i], val_b[i]);
}
fclose(fp);
return 0;
}
Using this text file as input:
A abc 12 34
B def 24 68
C ghi 35 79
gives the following output:
Line 1: A -- abc -- 12 -- 34
Line 2: B -- def -- 24 -- 68
Line 3: C -- ghi -- 35 -- 79

error: used struct type value where scalar is required

I am creating a program which takes an input and opens a text file and changes words to lower or upper case depending on what the user wants. When I compile the program I gets the following error:
22:11: error: used struct type value where scalar is required
30:11: error: used struct type value where scalar is required
1 #include <stdio.h>
2 int main(void) {
3
4 char choice;
5 char fileName;
6 char newFileName;
7 int i = 0;
8
9 printf("Change Case \n");
10 printf("============\n");
11 printf("Case (U for upper, L for lower) : ");
12 scanf(" %c", &choice);
13 printf("Name of the original file : oldFile.txt \n");
14 printf("Name of the updated file : newFile.txt \n");
15
16 FILE *fp = NULL;
17
18 fp = fopen("oldFile.txt", "a");
19
20 if (fp != NULL && choice == 'L') {
21
22 while ( fp[i] ) {
23
24 putchar(tolower(fp[i]));
25 i++;
26 }
27 }
28 else if (fp != NULL && choice == 'U') {
29
30 while ( fp[i] ) {
31
32 putchar(toupper(fp[i]));
33 i++;
34 }
35 }
36 else {
37
38 printf("ERROR: No proper choice was made \n");
39 }
40 }
fp is a file pointer, not an array of whats in your file. Have a look at use of fopen in a tutorial.
You will need to use something like fgets to read your file into a buffer. You can also use fgetc to read your file one character at a time.
wrong way accessing file pointer fp. It is an pointer to a file not a array character or string. Each time a file is opened, the system places the file pointer at the beginning of the file, which is offset zero.
Close the opened file every time after processing using fclose(fP);
sample example code snippet of using file pointer.
int c;
fp = fopen("file.txt","r");
while(1)
{
c = fgetc(fp);// or fgets as per the usage
if( c==EOF)
{
//Exit
}
// your code
}
fclose(fp);
The file pointer is not an array... consider using fgetc/fgets. fp[i] doesn't give you the i-th byte of the file. fgetc will let you iterate over the bytes of the file and return EOF when you're at the end.
See the documentation for fgetc here.
Here is an example on how to acquire strings from txt. There are many other ways
#include <stdio.h>
int main(void) {
FILE *fp;
fp = fopen("oldFile.txt", "r");
char str[1024];
while(fgets(str, 1024, fp)!=NULL) { //acquire strings from oldFile.txt through fgets() which returns a pointer. NULL is returned at the end of file
printf("%s", str); //just an example
}
}

hexdump output vs xxd output

I'm trying to create a hexdump like xxd but there are some differences that I'm trying to resolve. Currently the program processes 10 characters per line as seen on the utmost right column vs 16 in xxd. It also only shows 1 octet per column instead of pairs of 2 octet's.
xxd
0000000: 2369 6e63 6c75 6465 203c 7374 6469 6f2e #include <stdio.
my output
0: 23 69 6E 63 6C 75 64 65 20 3C #include <
EDIT:
To add some clarification, I am trying to achieve two things.
1) I would like this program to output exactly like xxd. For this it needs to output 32 Hex numbers (8x columns of 4).
2) I would also like the program to list the hex numbers in row's columns of 4 like in xxd.
I've tried to edit the "10" in the source below to something like "12" but it creates errors in the output, it seems to be a magic number.
source:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#define BYTE_OFFSET_INIT 8
#define CHAR_OFFSET_INT 39
#define LINE_LENGTH 50
static void print_e(int e, char *program, char *file)
{
fprintf(stderr, "%s: %s: %s\n", program, file, strerror(e));
}
static void print_line(char *line)
{
int i;
/* sprintf leaves terminators mid-line, so clear them out so we can print the full line */
for (i = BYTE_OFFSET_INIT; i < CHAR_OFFSET_INT; i++)
if (line[i] == '\0')
line[i] = ' ';
printf("%s\n", line);
}
int main(int argc, char *argv[])
{
char line[LINE_LENGTH + 1];
int ch;
int character = 0;
int line_offset = 0;
int byte_offset = BYTE_OFFSET_INIT, char_offset = CHAR_OFFSET_INT;
if (argc != 2) {
fprintf(stderr, "Usage: %s [file]\n", argv[0]);
exit(EXIT_FAILURE);
}
FILE *fp = fopen(argv[1], "rb");
if (!fp) {
print_e(errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
printf("Offset Bytes Characters\n");
printf("------ ----------------------------- ----------\n");
while ((ch = fgetc(fp)) != EOF) {
if (character == 0) {
sprintf(line, "%6d ", line_offset);
line_offset += 10;
}
sprintf(line + byte_offset, "%02X ", ch);
sprintf(line + char_offset, "%c", isprint(ch) ? ch : '.');
character++;
char_offset++;
byte_offset += 3;
if (character == 10) {
print_line(line);
character = 0;
char_offset = CHAR_OFFSET_INT;
byte_offset = BYTE_OFFSET_INIT;
}
}
if (ferror(fp)) {
print_e(errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
if (character > 0)
print_line(line);
if (fclose(fp) == EOF) {
print_e(errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
return 0;
}
While it's possible to scan one byte at a time and write it into the output string at the correct position, it is by no means necessary. It is way easier to read DISPLAY_LENGTH bytes at once and loop over the thus read number of bytes twice; first outputting the hex representation, then again for the ASCII characters. The only (minor) caveat is what to do at the end of the file; but since fread returns the number of characters, you can just keep on counting and output spaces for as long as necessary to fill the hex line.
This leads to the following program. DISPLAY_LENGTH is the total number of bytes to display per line, GROUP_BYTES is the number of single bytes in each hexadecimal group (setting it to 1 will display a 'regular' spaced hex output, 2 will group as in your xxd example, and higher values should also work).
I had some fun figuring out the magic formulae to correctly center the text Bytes and calculating how many dashes to display for the separator. The rest is very straightforward.
I don't know what xxd output looks like, apart from your one-line example, so I use stat to read out the length of the file in advance (with an added opportunity to display an error for "not a file" -- try for example with a folder) and display the correct number of dashes and spaces to line up the line counter. I set this value to a minimum of 6 so there is always room for the text Offset.
If your compiler is not a modern one, it may complain about the %zu format string. If so, use %lu; you may also need to change all occurrences of size_t to unsigned long.
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#define DISPLAY_LENGTH 21
#define GROUP_BYTES 2
static void print_e(int e, char *program, char *file)
{
fprintf(stderr, "%s: %s: %s\n", program, file, strerror(e));
}
int main(int argc, char *argv[])
{
size_t i;
struct stat fs;
int n_digit;
unsigned char read_buf[DISPLAY_LENGTH];
size_t bytes_read, cpos = 0;
if (argc != 2)
{
fprintf(stderr, "Usage: %s [file]\n", argv[0]);
exit(EXIT_FAILURE);
}
FILE *fp = fopen(argv[1], "rb");
if (!fp)
{
print_e (errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
if (stat(argv[1], &fs) == -1)
{
print_e (errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
if ((fs.st_mode & S_IFMT) != S_IFREG) /* regular file */
{
fprintf(stderr, "Not a regular file: %s\n", argv[1]);
exit(EXIT_FAILURE);
}
n_digit = 0;
while (fs.st_size > 0)
{
fs.st_size /= 10;
n_digit++;
}
if (n_digit < 6)
n_digit = 6;
printf("%*s ", n_digit, "Offset");
printf("%*s%-*s", ((2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES)+2)/2, "Bytes", ((2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES)+2-5)/2, "");
printf (" Characters\n");
for (i=0; i<n_digit; i++)
printf ("-");
printf(" ");
for (i=1; i<2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES; i++)
printf ("-");
printf (" ");
for (i=0; i<DISPLAY_LENGTH; i++)
printf ("-");
printf ("\n");
while ( (bytes_read = fread (read_buf, 1, DISPLAY_LENGTH, fp)))
{
printf ("%*zu ", n_digit, cpos);
for (i=0; i<bytes_read; i++)
{
if (!(i % GROUP_BYTES))
printf (" ");
printf ("%02X", read_buf[i]);
}
while (i < DISPLAY_LENGTH)
{
if (!(i % GROUP_BYTES))
printf (" ");
printf (" ");
i++;
}
printf (" ");
for (i=0; i<bytes_read; i++)
printf ("%c", isprint(read_buf[i]) ? read_buf[i] : '.');
printf ("\n");
cpos += bytes_read;
}
if (ferror(fp))
{
print_e (errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
if (fclose(fp))
{
print_e (errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
return 0;
}
Sample output, displaying its own compiled executable with a display length of 21 and grouped per 2 bytes:
Offset Bytes Characters
------ ---------------------------------------------------- ---------------------
0 CFFA EDFE 0700 0001 0300 0080 0200 0000 0D00 0000 70 ....................p
21 0600 0085 0020 0000 0000 0019 0000 0048 0000 005F 5F ..... .........H...__
42 5041 4745 5A45 524F 0000 0000 0000 0000 0000 0000 00 PAGEZERO.............
... (673 very similar lines omitted) ...
14196 7075 7473 005F 7374 6174 2449 4E4F 4445 3634 005F 73 puts._stat$INODE64._s
14217 7472 6572 726F 7200 6479 6C64 5F73 7475 625F 6269 6E trerror.dyld_stub_bin
14238 6465 7200 0000 der...

Why doesn't fgets read whole line in while loop but works in for loop?

If my fgets is in a while loop, it only returns half the string. If it's in a for loop, it returns the whole string.. Any idea why?
Code below:
FILE *fp; // File pointer
char filename[] = "results.tsv";
fp = fopen(filename, "r"); // Open file argv[1] for READ
char s[4096];
int num = atoi(fgets(s, sizeof(s), fp)); // Get first line (number of units in file)
int i;
for(i = 0; i < num; i++)
{
printf("%s", fgets(s, sizeof(s), fp)); // Prints everything
}
while (fgets(s, sizeof(s), fp) != NULL) // Loop until no more lines
{
printf("%s\n", s); // Only prints the x's
}
fclose(fp); // Close file
And the files contents:
1
xxxxxxxx yyyy eee
Where the big spaces are tabs (\t).
If I run it, I get:
For loop only:
xxxxxxxx yyyy eee
While loop only:
xxxxxxxx
Thanks.
As already diagnosed, your code 'works for me'. Here's the SSCCE I created for it. If invoked with no arguments, it uses the while loop. If invoked with any arguments, it uses the for loop. Either way, it works correctly for me. Note that the code doesn't use the return value from fgets() directly; it checks that the input operation succeeded before doing so. It also echos what it is doing and reading as it goes.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
FILE *fp;
char filename[] = "results.tsv";
if ((fp = fopen(filename, "r")) == 0)
{
fprintf(stderr, "%s: failed to open file %s\n", argv[0], filename);
exit(1);
}
char s[4096];
if (fgets(s, sizeof(s), fp) == 0)
{
fprintf(stderr, "Premature EOF\n");
exit(1);
}
int num = atoi(s);
printf("Num lines: %d\n", num);
if (argc > 1)
{
printf("For loop:\n");
for (int i = 0; i < num; i++)
{
if (fgets(s, sizeof(s), fp) == 0)
{
fprintf(stderr, "Premature EOF\n");
exit(1);
}
printf("%d: %s", i+1, s);
}
}
else
{
int i = 0;
while (fgets(s, sizeof(s), fp) != NULL)
{
printf("While loop:\n");
printf("%d: %s", ++i, s);
}
}
fclose(fp);
return 0;
}
If you use this code and it fails on your system, then you could submit your evidence. Amongst other things, you should identify the platform on which you're working, and you should give a hex dump (or equivalent) of the data in the file results.tsv. The data file I used, for example, contained the bytes:
0x0000: 31 0A 78 78 78 78 78 78 78 78 09 79 79 79 79 09 1.xxxxxxxx.yyyy.
0x0010: 65 65 65 65 0A eeee.
0x0015:
Before start reading with while loop, you have to make the position of reading from the stream(file) start at the same position where the for loop start reading
You can do it with one of the 2 ways:
1) close the file and reopen it and read the first line before starting the while loop
2) Use the fseek (as KiriliKirov said) to point at the same position where the for loop start reading. To do you have get the current position (position where the for loop start reading) with the ftell() function:
int num = atoi(fgets(s, sizeof(s), fp));
long int start_read = ftell (fp); // get the current postion //add this line in your code
.....
fseek ( fp , start_read , SEEK_SET ); // add this line in your code
while (fgets(s, sizeof(s), fp) != NULL)
The second solution will avoid the close and the reopen the file and the read of the first line.
ftell() returns the current value of the position indicator of the stream.
fseek() Sets the position indicator associated with the stream to a new position

Resources