read the header of a .pgm image file - c

I am attempting to read the size values from the header of a .pgm image file (mars.pgm), and assign the resulting values to the integer variables u and v using sscanf.
When executed the program prints P5 832 700 127 in the first line, which is correct (the 832 and 700 are the size values that I want to pick out).
In the second line that is meant to print u and v variables two very large numbers are printed, instead of the 832 and 700 values.
I cannot figure out why this is not working as desired. When using the small test program (located at the bottom of the post) sscanf picks out the values from a string like I expected it to.
#include<stdio.h>
#include <string.h>
int main()
{
FILE *fin;
fin= fopen ("mars.pgm","r+");
if (fin == NULL)
{
printf ("ERROR");
fclose(fin);
}
int u,v,i,d,c;
char test[20];
for (i=0; i<=20; i++)
{
test[i]=getc(fin);
}
sscanf(test,"%d,%d,%d,%d",&c,&u,&v,&d);
printf("%s\n",test);
printf("%d %d",u, v);
fclose(fin);
}
small test Program
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(void)
{
int a;
char s[3];
s[0]='1';
s[1]=' ';
s[2]='2';
sscanf(s,"%d",&a);
printf("%d",a);
}

First of all, I advise you to make a small test: initialize your variables with a 0, for instance, and verify what value they are holding after read operation.
Then, try removing , characters from your format string. Check if it works then.
This behavior you see is happening because fscanf() and derivatives match the full pattern when scanning, which means if your source data has no commas and your format has commas, it may be ignored.

Related

How to Split strings with fgets or fscanf in C?

I understand how to read in a text file and scan/print the entire file, but how can a line be split into several strings? Also, can variables be assigned to those strings to be called later?
My code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fPointer;
fPointer = fopen("p1customer.txt", "r");
char singleLine[150];
int id;
while (!feof(fPointer)){
fscanf(fPointer, "%d", &id);
printf("%d",id);
}
fclose(fPointer);
return 0;
}
Example Text File to be read:
99999 John Doe Basketball
Example Output:
John Doe has ID number 99999 and plays Basketball
I am attempting to split/tokenize those strings and assign them variables (IDnumber, Name, Sport) and print the output in a new file.
you can use a library function strtok(str,chrs) function.
A sequence of calls of strtok(str,chrs) splits str into tokens, each delimited by a character from chrs.
The first call in a sequence is a non Null str.It finds the first token in str consisting of chars not int chrs;it terminates that by overwrtting the next characters of str by \0 and return pointer to token. Each subsequent call,indicated by a NULL value of str,retuens a pointer to next such token, searching from just past the end of privious one.
You should post an example of the input file so that you can help in more detail.
I've seen you've also entered a string, I guess you want to fill in with something but you did not specify that.
If you wanted to treat the file as a list of numbers, the sample of the code might be the following.
#include <stdio.h>
int main() {
FILE *infile;
char buf[100];
int len_file=0;
if(!(infile = fopen("p1customer.txt", "r"))) { /*checks the correct opening of the file*/
printf("Error in open p1customer.txt\n");
return 1;
}
while(fgets(buf,sizeof(buf),infile)!=NULL) /*check the lenght of the file (number of row) */
len_file++;
int id[len_file];
int i=0;
rewind(infile);
while(fgets(buf,sizeof(buf),infile)!=NULL) {
sscanf(buf,"%i",&id[i]);
i++;
}
for(i=0;i<len_file;i++)
printf("%i\n",id[i]);
fclose(infile);
return 0;
}
If you want to treat the file as an indefinite list of numbers on each row separated by a space, you can use the parsing of the string by using in the sscanf formatting %31[^ ]which has the task of reading the number until it encounters a space, also you can add a variable that is incremented for each char/number read.
Then you can refine the code by checking if there are any characters in the line using the isalpha function in the ctype.h library to see if there are any characters and then insert them into a string until you find the termination character '\ 0'.
The possibilities are infinite so it would useful have the input file, when you provided it, i'll update the answer.

Unable to retain array outside the while loop

I am currently working on the C code below. I need to access the array outside the while loop, after fclose. It appears that the blackfin ADSP kernel crashes every time I run it. I will need it further to perform FFT. Please help!
#include <stdlib.h>
#include <stdio.h>
#include <flt2fr.h>
#include <fract_math.h>
#include <math_bf.h>
#include <complex.h>
#include <filter.h>
int main()
{
int n = 1024;
long int dat1[n];
FILE *file1;
fract16 *m;
int i;
// file1 open and read the values
file1 = fopen("0.dat", "r");
if (file1 == NULL) {
printf("I couldn't open 0.dat for reading.\n");
exit(0);
}
while (!feof(file1)) {
fgets(dat1, n, file1);
m = malloc(sizeof(fract16) * n);
for (i = 0; i < n; i++) {
sscanf(dat1, "%f", &m[i]); //getting error here
}
}
fclose(file1);
printf("%lf\n", m);
return 0;
}
Alright, thank you all for correcting my mistakes, but the problem is still unresolved. I am able to print all of the values inside, but outside the loop it prints just the last value of the data set, is there any precise solution for this? I googled for hours but no success yet.
The code is as follows >
#include <stdlib.h>
#include <stdio.h>
#include <flt2fr.h>
#include<fract_math.h>
#include <math_bf.h>
#include <complex.h>
#include <filter.h>
int main()
{
int n = 1024;
long int dat1[n];
FILE *file1;
fract16 *m;
file1 = fopen("0.dat", "r");
if (file1 == NULL) {
printf("I couldn't open 0.dat for reading.\n");
exit(0);
}
while( !feof(file1))
{
fgets(dat1,n,file1);
sscanf(dat1, "%f", &m);
printf("%f\n",m); //Prints all elements in the 1st column of the array, 0.dat is a nx2 matrix
}
fclose(file1);
}
You can allocate memory for the buffer before reading the file, outside the while loop. Then every time before reading into the buffer, simply use memset and set the buffer to all null characters.
Also, try using fread to read directly into the buffer rather than fgets
the variable m is defined as a pointer to and array of fract16
to fix the problem suggest:
if( 1 != sscanf(dat1, "%f", m+(sizeof(fract16)*i) )
{
perror( "sscanf failed" );
exit( EXIT_FAILURE );
}
The error is being cause because m is already a pointer and you want it to continue to be a pointer
As an aside. the code is not checking how much data was actually read in the call to fgets() so the for() may very well be reading behond the end of the actual data. And each trip through the while() loop is destroying/overlaying the pointer obtained from the prior call to malloc()
then later in the code is the statement:
printf("%lf\n", m);
But m is a pointer to an array of `fract16 objects.
and those fract16 objects might be double values, but that detail is not clear. In any case, this call to printf() will, at best, only output a single double value from the beginning of the last line in the input file. Is that what you really want to do?
Note: dat1[] is declared as an array of long int, but the call to sscanf() seems to be trying to extract float values.
I.E. the code is not consistent about the data types, nor the extraction of individual values, nor the printing.
One thing to note: with the current code there is a massive memory leak due to the pointer m being repeatedly overwritten by the calls to malloc() And due to the use of feof(), the last call to fgets() will fail, so the cotents of dat1[] will be starting with a NUL byte
Suggest allocating an array of pointers to fractl16 objects
Then for each line read, use malloc() to set the next pointer in the array of pointers, ...

I'm unable to calculate the entropy of a .exe file

I'm trying to calculate the entropy of a .exe file by giving it as an input. However, I'm getting a zero value instead of an answer.
Entropy of a file can be understood as the the summation of (pi*log(pi)) every character in the file. I'm trying to calculate the entropy of a .exe file. However, I'm ending up getting a '0'. The '.exe' file for sure has an output.
Below is my code.
#include <stdio.h>
#include <stdlib.h>
#include "stdbool.h"
#include <string.h>
#include <conio.h>
#include <math.h>
#define MAXLEN 100
int makehist( char *S, int *hist, int len) {
int wherechar[256];
int i,histlen;
histlen=0;
for (i=0;i<256;i++)
wherechar[i]=-1;
for (i=0;i<len;i++) {
if (wherechar[(int)S[i]]==-1) {
wherechar[(int)S[i]]=histlen;
histlen++;
}
hist[wherechar[(int)S[i]]]++;
}
return histlen;
}
double entropy(int *hist, int histlen, int len) {
int i;
double H;
H=0;
for (i=0;i<histlen;i++) {
H-=(double)hist[i]/len*log((double)hist[i]/len);
}
return H;
}
void main() {
char S[100];
int len,*hist,histlen;
int num;
double H;
int i=0;
int count =0;
FILE*file = fopen("freq.exe","r");
while (fscanf(file,"%d",&num)>0)
{
S[i]=num;
printf("%d",S[i]);
i++;
}
hist=(int*)calloc(i,sizeof(int));
histlen=makehist(S,hist,i);
H=entropy(hist,histlen,i);
printf("%lf\n",H);
getch();
}
while (fscanf(file,"%d",&num)>0)
This reads numbers encoded as leading white space, optional sign, and a sequence of digits. As soon as some other character is encountered in your file (probably the first byte), your loop will stop. You need to read raw bytes, with getc or fread.
Also, please consider doing the most basic debugging before submitting a question to StackOverflow. Surely your printf in that loop never printed anything, yet you don't mention this in your question and apparently didn't investigate why.
Some other issues:
#define MAXLEN 100
This is never used.
void main()
This is not a valid definition of main. Use
int main(void)
char S[100];
You have undefined behavior if the input contains more than 100 chars, and a .exe file surely will. You really should be feeding the bytes into your histogram calculation as you read them, rather than storing them in a buffer. Easiest is to make wherechar and histlen globals, but you could also put everything you need into a struct and pass a pointer to the struct, together with each byte, to makehist, and again pass a pointer to the struct to entropy.
FILE*file = fopen("freq.exe","r");
Binary files must be opened with "rb" (doesn't matter on linux but does on Windows).
Also, you should check whether fopen succeeds.
hist=(int*)calloc(i,sizeof(int));
hist should have 256 elements. If you allocate this first, then you can process each byte as it is read per above.
You do a divide by zero in entropy if the file is empty ... you should check for len == 0.
wherechar[(int)S[i]] is undefined behavior if the file has chars with negative values, as it surely will. You should use unsigned char instead of char, and then the casts aren't necessary.
This line seems to be reading numbers:
fscanf(file,"%d",&num)
But I don't really expect to find many numbers in an EXE file.
They'd be random byte-values of all different types.
Numbers are only the digits 0-9 (and - & + signs as well).

Read CSV into array to sort numerically by numbers given in the lines

I try to read a temporary file consisting of several lines like the following example. The lines are NOT sorted.
3;NOK
2;OK
1;NA
For an easy output-function, in which I want to offer several possibilities of output (CSV, Print on Screen...), I thought it would be clever to do the following.
Open the file
Iterate through the lines
Extract the number at the beginning
Use this as index of an array
The result should be a "sorted" array
A minimal example which gives me an Segmentation Fault.
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char *argv[]){
FILE *outfp = fopen("test.txt", "r");
if (outfp == NULL){
printf("There was a problem: Temporary output-file could not be opened");
return 1;
}
// OUTPUT HANDLING
char output_line[1024];
char output_cut[1024];
int line_number;
char *output_array[3]; //The maximum number of possible entries is fixed
// I got variables for the line, for the linenumber and output_cut is needed for sscanf
while(fgets(output_line, sizeof(output_line), outfp)!=NULL){
sscanf(output_line,"%d;%s",&line_number,output_cut);
output_array[line_number]=output_line;
}
printf("LINE1:%s",output_array[1]);
printf("LINE2:%s",output_array[2]);
printf("LINE3:%s",output_array[3]);
return 0;
}
My first question: Is this the right way to do, or are there other better ways to "sort" this kind of file in an easy way for flexible output?
If yes, why does this not work?
Regards
Markus
Edit: the example textfile just contains numbers from 1-3... not 13,14...
Edit2: the solution
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[]){
FILE *outfp = fopen("test.txt", "r");
if (outfp == NULL){
printf("There was a problem: Temporary output-file could not be opened");
return 1;
}
// OUTPUT HANDLING
char output_line[1024];
char output_cut[1024];
int line_number;
char output_array[4][1024]; //The maximum number of possible entries is fixed
// I got variables for the line, for the linenumber and output_cut is needed for sscanf
while(fgets(output_line, sizeof(output_line), outfp)!=NULL){
sscanf(output_line,"%d;%s",&line_number,output_cut);
strcpy(output_array[line_number],output_line);
}
printf("LINE1: %s",output_array[1]);
printf("LINE2: %s",output_array[2]);
printf("LINE3: %s",output_array[3]);
return 0;
}
You have two major problems with the code as shown in the question. The first is that all the pointers in the output_array points to the same place. This means that when you print the lines all will print the same (which will be the last line read).
The second problem is your array indexing. Array indices goes from zero to the size minus one, so for your output_array the indices are 0 to 2 (inclusive). The problem causing the crash is that you use index 3 which is out of bound for the array, and leads to undefined behavior.

Get numbers only from a text file using c

/edited/
I'm new here.
I have a text file that reads:
6
<cr>
R 0
R 1
R 4
R 36
R 0
R 4
This is what I have. I want to read each line into an array so that I can convert that array into an integer so I can print only the numbers of whichever line I want later.
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main()
{
FILE *fr; /*declares file pointer*/
int i, j, num[32];
char array[32][32], input_file[32], line[32];
printf("Enter file: ");
fflush(stdin);
scanf("%s", input_file);
fr = fopen(input_file, "r");
for(i=0;i<32;i++)
for(j=0;j<32;j++){
array[i][j] = \'0';
}
for(i=0;i<32;i++){
line[i] = '\0';
}
if(fr != NULL){
while(fgets(line, sizeof(line), fr) != NULL){
strcpy(array[i],line);
num[i] = atoi(array[i]);
i++;
printf("%d\n", num[i]);
}
}fclose(fr);
else{
perror(input_file);
}
}
I'm not getting any errors but it isn't printing the right thing; this is what it prints:
-370086
-370086
-370086
-370086
-370086
-370086
-370086
-370086
Can anyone explain to me what is going wrong?
I think I'd handle this a bit differently. Though you haven't stated it explicitly, I'm going to assume that the first number is telling us how many more lines of letters/numbers we're going to read (not including the blank line). So, we want to read that, then read the rest of the lines, ignoring any leading non-digits, paying attention only to the numbers.
If that's correct, we can simplify the code somewhat:
int num_lines;
int i;
int *numbers;
fscanf(infile, "%d", &num_lines); // read the number of lines.
numbers = malloc(sizeof(int) * num_lines); // allocate storage for that many numbers.
// read that many numbers.
for (i=0; i<num_lines; i++)
fscanf(infile, "%*[^0123456789]%d", numbers+i);
// the "%*[^0123456789]" ignores leading non-digits. The %d converts a number.
There are several issues:
You're never setting input_file to anything, so you seem to be opening a random file.
You're double-using i in the nested loops.
You're not showing array at all, so it's impossible to tell how it's declared.
You are increasing the loop index before using it to print the number, so you're always "missing" and printing the number in the next (not yet written) slot.
You should use memset() to clear the arrays if you're worried. There's no need to clear arrays that are going to be overwritten, such as line which is written to by fgets().
Assuming array is a char array, when you do:
...
strcpy(array[i],line);
num[i] = atoi(array[i]);
...
Your actually converting the entire line and not the integer in it. You should consider using fscanf, or at least search for the integer inside the line variable and convert it.
Doing atoi(array[i]) is the same as atoi("R 32\n") for example.

Resources