creating a bitmap image from existing bitmap, in C - c

I am writing a C program, which will retrieve the information (header information, pixel information) from a bitmap image, and use that information to create another bitmap image (the new image will obviously be same as the original).
The problem is that, in some cases, extra bytes get added (on their own) to the new image, due to which the image is not formed properly.
In another case, some bytes get missing in the new image, due to which image formation itself fails.
(This happens while writing the pixel information. the bitmap header information gets written properly to the new file.)
I have debugged the code but I couldn't find out what is causing this.
I'll be glad if somebody could tell me what the error is.
//creating a bitmap file
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<math.h>
long extract(FILE *,long ,int );
long extract(FILE *fp1,long offset,int size)
{
unsigned char *ptr;
unsigned char temp='0';
long value=0L;
int i;
//to initialize the ptr
ptr=&temp;
//sets the file pointer at specific position i.e. after the offset
fseek(fp1,offset,SEEK_SET);
//now fgetcing (size) values starting from the offset
for(i=1;i<=size;i++)
{
fread(ptr,sizeof(char),1,fp1);
value=(long)(value+(*ptr)*(pow(256,(i-1)))); //combining the values one after another in a single variable
}
return value;
}
int main()
{
int row,col;
int i,j,k;
int dataoffset,offset;
char magicnum[2];
FILE *fp1,*fp4;
clrscr();
if((fp1=fopen("stripes.bmp","rb"))==NULL)
{
printf("\a\nCant open the image.\nSystem is exiting.");
exit(0);
}
if((fp4=fopen("op.bmp","a"))==NULL)
{
printf("\n\aError while creating a file.\nSystem is exiting ..... ");
exit(0);
}
fputc((int)extract(fp1,0L,1),fp4);
fputc((int)extract(fp1,1L,1),fp4);
fputc((int)extract(fp1,2L,1),fp4);
fputc((int)extract(fp1,3L,1),fp4);
fputc((int)extract(fp1,4L,1),fp4);
fputc((int)extract(fp1,5L,1),fp4);
fputc((int)extract(fp1,6L,1),fp4);
fputc((int)extract(fp1,7L,1),fp4);
fputc((int)extract(fp1,8L,1),fp4);
fputc((int)extract(fp1,9L,1),fp4);
fputc((int)extract(fp1,10L,1),fp4);
fputc((int)extract(fp1,11L,1),fp4);
fputc((int)extract(fp1,12L,1),fp4);
fputc((int)extract(fp1,13L,1),fp4);
fputc((int)extract(fp1,14L,1),fp4);
fputc((int)extract(fp1,15L,1),fp4);
fputc((int)extract(fp1,16L,1),fp4);
fputc((int)extract(fp1,17L,1),fp4);
fputc((int)extract(fp1,18L,1),fp4);
fputc((int)extract(fp1,19L,1),fp4);
fputc((int)extract(fp1,20L,1),fp4);
fputc((int)extract(fp1,21L,1),fp4);
fputc((int)extract(fp1,22L,1),fp4);
fputc((int)extract(fp1,23L,1),fp4);
fputc((int)extract(fp1,24L,1),fp4);
fputc((int)extract(fp1,25L,1),fp4);
fputc((int)extract(fp1,26L,1),fp4);
fputc((int)extract(fp1,27L,1),fp4);
fputc((int)extract(fp1,28L,1),fp4);
fputc((int)extract(fp1,29L,1),fp4);
fputc((int)extract(fp1,30L,1),fp4);
fputc((int)extract(fp1,31L,1),fp4);
fputc((int)extract(fp1,32L,1),fp4);
fputc((int)extract(fp1,33L,1),fp4);
fputc((int)extract(fp1,34L,1),fp4);
fputc((int)extract(fp1,35L,1),fp4);
fputc((int)extract(fp1,36L,1),fp4);
fputc((int)extract(fp1,37L,1),fp4);
fputc((int)extract(fp1,38L,1),fp4);
fputc((int)extract(fp1,39L,1),fp4);
fputc((int)extract(fp1,40L,1),fp4);
fputc((int)extract(fp1,41L,1),fp4);
fputc((int)extract(fp1,42L,1),fp4);
fputc((int)extract(fp1,43L,1),fp4);
fputc((int)extract(fp1,44L,1),fp4);
fputc((int)extract(fp1,45L,1),fp4);
fputc((int)extract(fp1,46L,1),fp4);
fputc((int)extract(fp1,47L,1),fp4);
fputc((int)extract(fp1,48L,1),fp4);
fputc((int)extract(fp1,49L,1),fp4);
fputc((int)extract(fp1,50L,1),fp4);
fputc((int)extract(fp1,51L,1),fp4);
fputc((int)extract(fp1,52L,1),fp4);
fputc((int)extract(fp1,53L,1),fp4);
//setting the file pointer at the beginning
rewind(fp1);
/*CHECKING WHETHER THE FILE IS IN BMP FORMAT OR NOT, WE CHECK THE MAGIC NUMBER OF THE FILE, MAGIC NUMBER'S OFFSET IS 0 i.e. IT'S STORED AT THE FRONT OF THE IMAGE, AND THE SIZE IS 2*/
//at first extracting the magic number
for(i=0;i<2;i++)
{
magicnum[i]=(char)extract(fp1,i,1);
}
//now checking
if((magicnum[0]=='B') && (magicnum[1]=='M'))
;
else
{
printf("\aThe image is not a bitmap image.\nSystem is exiting ... ");
exit(0);
}
//storing the header information
//get the starting position or offset of the data(pixel)
dataoffset=(int)extract(fp1,10,4);
//get the number of rows
row=(int)extract(fp1,22,4);
//get the number of columns
col=(int)extract(fp1,18,4);
//storing the data
offset=dataoffset;
for(j=0;j<col;j++)
{
for(k=0;k<row;k++)
{
for(i=0;i<=2;i++)
{
fputc((int)extract(fp1,offset++,1),fp4);
}
}
}
fcloseall();
return 0;
}

Make sure you open the output file in binary mode as well.
If you don't do that, the byte value corresponding to '\n' may be expanded to carriage return and line feed.

Consider this line:
value=(long)(value+(*ptr)*(pow(256,(i-1))));
pow is a floating point function returning a double. This means that (*ptr) is implicitly casted to double. The whole expression (value+(*ptr)*(pow(256,(i-1)))) will be a double. Now this can be larger than 2147483647 which is the largest number a long can hold (on most common 32-bit platforms), and the result when converting an out of range double to long is undefined. See what happens on this example:
#include <stdio.h>
int main(int argc, char **argv) {
int i;
for (i = 0; i < 10; i++) {
double d = 2147483647.0d + i;
printf("double=%f long=%ld\n", d, (long)d);
}
return 0;
}
Here is the output when I run it on my system: (hidden in case you want to guess or test it yourself first):
double=2147483647.000000 long=2147483647
double=2147483648.000000 long=-2147483648
double=2147483649.000000 long=-2147483648
double=2147483650.000000 long=-2147483648
double=2147483651.000000 long=-2147483648
double=2147483652.000000 long=-2147483648
double=2147483653.000000 long=-2147483648
double=2147483654.000000 long=-2147483648
double=2147483655.000000 long=-2147483648
double=2147483656.000000 long=-2147483648
One way to fix it would be to change it to unsigned long instead.
Personally I'd use 1 << (8*(i-1)) instead of pow to avoid messing with floating point, but there is lots of other things that I'd do very different too, but that is probably out of scope for this question (might be a question for the code review site).

Related

How to read imaginary data from text file, with C

I am unable to read imaginary data from text file.
Here is my .txt file
abc.txt
0.2e-3+0.3*I 0.1+0.1*I
0.3+0.1*I 0.1+0.4*I
I want to read this data into a matrix and print it.
I found the solutions using C++ here and here. I don't know how to do the same in C.
I am able to read decimal and integer data in .txt and print them.
I am also able to print imaginary data initialized at the declaration, using complex.h header. This is the program I have writtern
#include<stdio.h>
#include<stdlib.h>
#include<complex.h>
#include<math.h>
int M,N,i,j,k,l,p,q;
int b[2];
int main(void)
{
FILE* ptr = fopen("abc.txt", "r");
if (ptr == NULL) {
printf("no such file.");
return 0;
}
long double d=0.2e-3+0.3*I;
long double c=0.0000000600415046630252;
double matrixA[2][2];
for(i=0;i<2; i++)
for(j=0;j<2; j++)
fscanf(ptr,"%lf+i%lf\n", creal(&matrixA[i][j]), cimag(&matrixA[i][j]));
//fscanf(ptr, "%lf", &matrixA[i][j]) for reading non-imainary data, It worked.
for(i=0;i<2; i++)
for(j=0;j<2; j++)
printf("%f+i%f\n", creal(matrixA[i][j]), cimag(matrixA[i][j]));
//printf("%lf\n", matrixA[i][j]); for printing non-imainary data, It worked.
printf("%f+i%f\n", creal(d), cimag(d));
printf("%Lg\n",c);
fclose(ptr);
return 0;
}
But I want to read it from the text, because I have an array of larger size, which I can't initialize at declaration, because of it's size.
There are two main issues with your code:
You need to add complex to the variables that hold complex values.
scanf() needs pointers to objects to store scanned values in them. But creal() returns a value, copied from its argument's contents. It is neither a pointer, nor could you get the address of the corresponding part of the complex argument.
Therefore, you need to provide temporary objects to scanf() which receive the scanned values. After successfully scanning, these values are combined to a complex value and assigned to the indexed matrix cell.
Minor issues not contributing to the core problem are:
The given source is "augmented" with unneeded #includes, unused variables, global variables, and experiments with constants. I removed them all to see the real thing.
The specifier "%f" (as many others) lets scanf() skip whitespace like blanks, tabs, newlines, and so on. Providing a "\n" mostly does more harm than one would expect.
I kept the "*I" to check the correct format. However, an error will only be found on the next call of scanf(), when it cannot scan the next number.
You need to check the return value of scanf(), always! It returns the number of conversions that were successful.
It is a common and good habit to let the compiler calculate the number of elements in an array. Divide the total size by an element's size.
Oh, and sizeof is an operator, not a function.
It is also best to return symbolic values to the caller, instead of magic numbers. Fortunately, the standard library defines these EXIT_... macros.
The signs are correctly handled by scanf() already. There is no need to tell it more. But for a nice output with printf(), you use the "+" as a flag to always output a sign.
Since the sign is now placed directly before the number, I moved the multiplication by I (you can change it to lower case, if you want) to the back of the imaginary part. This also matches the input format.
Error output is done via stderr instead of stdout. For example, this enables you to redirect the standard output to a pipe or file, without missing potential errors. You can also redirect errors somewhere else. And it is a well-known and appreciated standard.
This is a possible solution:
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
int main(void)
{
FILE* ptr = fopen("abc.txt", "r");
if (ptr == NULL) {
perror("\"abc.txt\"");
return EXIT_FAILURE;
}
double complex matrixA[2][2];
for (size_t i = 0; i < sizeof matrixA / sizeof matrixA[0]; i++)
for (size_t j = 0; j < sizeof matrixA[0] / sizeof matrixA[0][0]; j++) {
double real;
double imag;
if (fscanf(ptr, "%lf%lf*I", &real, &imag) != 2) {
fclose(ptr);
fprintf(stderr, "Wrong input format\n");
return EXIT_FAILURE;
}
matrixA[i][j] = real + imag * I;
}
fclose(ptr);
for (size_t i = 0; i < sizeof matrixA / sizeof matrixA[0]; i++)
for (size_t j = 0; j < sizeof matrixA[0] / sizeof matrixA[0][0]; j++)
printf("%+f%+f*I\n", creal(matrixA[i][j]), cimag(matrixA[i][j]));
return EXIT_SUCCESS;
}
Here's a simple solution using scanf() and the format shown in the examples.
It writes the values in the same format that it reads them — the output can be scanned by the program as input.
/* SO 7438-4793 */
#include <stdio.h>
static int read_complex(FILE *fp, double *r, double *i)
{
int offset = 0;
char sign[2];
if (fscanf(fp, "%lg%[-+]%lg*%*[iI]%n", r, sign, i, &offset) != 3 || offset == 0)
return EOF;
if (sign[0] == '-')
*i = -*i;
return 0;
}
int main(void)
{
double r;
double i;
while (read_complex(stdin, &r, &i) == 0)
printf("%g%+g*I\n", r, i);
return 0;
}
Sample input:
0.2e-3+0.3*I 0.1+0.1*I
0.3+0.1*I 0.1+0.4*I
-1.2-3.6*I -6.02214076e23-6.62607015E-34*I
Output from sample input:
0.0002+0.3*I
0.1+0.1*I
0.3+0.1*I
0.1+0.4*I
-1.2-3.6*I
-6.02214e+23-6.62607e-34*I
The numbers at the end with large exponents are Avogadro's Number and the Planck Constant.
The format is about as stringent are you can make it with scanf(), but, although it requires a sign (+ or -) between the real and imaginary parts and requires the * and I to be immediately after the imaginary part (and the conversion will fail if the *I is missing), and accepts either i or I to indicate the imaginary value:
It doesn't stop the imaginary number having a second sign (so it will read a value such as "-6+-4*I").
It doesn't stop there being white space after the mandatory sign (so it will read a value such as "-6+ 24*I".
It doesn't stop the real part being on one line and the imaginary part on the next line.
It won't handle either a pure-real number or a pure-imaginary number properly.
The scanf() functions are very flexible about white space, and it is very hard to prevent them from accepting white space. It would require a custom parser to prevent unwanted spaces. You could do that by reading the numbers and the markers separately, as strings, and then verifying that there's no space and so on. That might be the best way to handle it. You'd use sscanf() to convert the string read after ensuring there's no embedded white space yet the format is correct.
I do not know which IDE you are using for C, so I do not understand this ./testprog <test.data.
I have yet to find an IDE that does not drive me bonkers. I use a Unix shell running in a terminal window. Assuming that your program name is testprog and the data file is test.data, typing ./testprog < test.data runs the program and feeds the contents of test.data as its standard input. On Windows, this would be a command window (and I think PowerShell would work much the same way).
I used fgets to read each line of the text file. Though I know the functionality of sscanf, I do not know how to parse an entire line, which has about 23 elements per line. If the number of elements in a line are few, I know how to parse it. Could you help me about it?
As I noted in a comment, the SO Q&A How to use sscanf() in loops? explains how to use sscanf() to read multiple entries from a line. In this case, you will need to read multiple complex numbers from a single line. Here is some code that shows it at work. It uses the POSIX getline() function to read arbitrarily long lines. If it isn't available to you, you can use fgets() instead, but you'll need to preallocate a big enough line buffer.
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#ifndef CMPLX
#define CMPLX(r, i) ((double complex)((double)(r) + I * (double)(i)))
#endif
static size_t scan_multi_complex(const char *string, size_t nvalues,
complex double *v, const char **eoc)
{
size_t nread = 0;
const char *buffer = string;
while (nread < nvalues)
{
int offset = 0;
char sign[2];
double r, i;
if (sscanf(buffer, "%lg%[-+]%lg*%*[iI]%n", &r, sign, &i, &offset) != 3 || offset == 0)
break;
if (sign[0] == '-')
i = -i;
v[nread++] = CMPLX(r, i);
buffer += offset;
}
*eoc = buffer;
return nread;
}
static void dump_complex(size_t nvalues, complex double values[nvalues])
{
for (size_t i = 0; i < nvalues; i++)
printf("%g%+g*I\n", creal(values[i]), cimag(values[i]));
}
enum { NUM_VALUES = 128 };
int main(void)
{
double complex values[NUM_VALUES];
size_t nvalues = 0;
char *buffer = 0;
size_t buflen = 0;
int length;
size_t lineno = 0;
while ((length = getline(&buffer, &buflen, stdin)) > 0 && nvalues < NUM_VALUES)
{
const char *eoc;
printf("Line: %zu [[%.*s]]\n", ++lineno, length - 1, buffer);
size_t nread = scan_multi_complex(buffer, NUM_VALUES - nvalues, &values[nvalues], &eoc);
if (*eoc != '\0' && *eoc != '\n')
printf("EOC: [[%s]]\n", eoc);
if (nread == 0)
break;
dump_complex(nread, &values[nvalues]);
nvalues += nread;
}
free(buffer);
printf("All done:\n");
dump_complex(nvalues, values);
return 0;
}
Here is a data file with 8 lines with 10 complex numbers per line):
-1.95+11.00*I +21.72+64.12*I -95.16-1.81*I +64.23+64.55*I +28.42-29.29*I -49.25+7.87*I +44.98+79.62*I +69.80-1.24*I +61.99+37.01*I +72.43+56.88*I
-9.15+31.41*I +63.84-15.82*I -0.77-76.80*I -85.59+74.86*I +93.00-35.10*I -93.82+52.80*I +85.45+82.42*I +0.67-55.77*I -58.32+72.63*I -27.66-81.15*I
+87.97+9.03*I +7.05-74.91*I +27.60+65.89*I +49.81+25.08*I +44.33+77.00*I +93.27-7.74*I +61.62-5.01*I +99.33-82.80*I +8.83+62.96*I +7.45+73.70*I
+40.99-12.44*I +53.34+21.74*I +75.77-62.56*I +54.16-26.97*I -37.02-31.93*I +78.20-20.91*I +79.64+74.71*I +67.95-40.73*I +58.19+61.25*I +62.29-22.43*I
+47.36-16.19*I +68.48-15.00*I +6.85+61.50*I -6.62+55.18*I +34.95-69.81*I -88.62-81.15*I +75.92-74.65*I +85.17-3.84*I -37.20-96.98*I +74.97+78.88*I
+56.80+63.63*I +92.83-16.18*I -11.47+8.81*I +90.74+42.86*I +19.11-56.70*I -77.93-70.47*I +6.73+86.12*I +2.70-57.93*I +57.87+29.44*I +6.65-63.09*I
-35.35-70.67*I +8.08-21.82*I +86.72-93.82*I -28.96-24.69*I +68.73-15.36*I +52.85+94.65*I +85.07-84.04*I +9.98+29.56*I -78.01-81.23*I -10.67+13.68*I
+83.10-33.86*I +56.87+30.23*I -78.56+3.73*I +31.41+10.30*I +91.98+29.04*I -9.20+24.59*I +70.82-19.41*I +29.21+84.74*I +56.62+92.29*I +70.66-48.35*I
The output of the program is:
Line: 1 [[-1.95+11.00*I +21.72+64.12*I -95.16-1.81*I +64.23+64.55*I +28.42-29.29*I -49.25+7.87*I +44.98+79.62*I +69.80-1.24*I +61.99+37.01*I +72.43+56.88*I]]
-1.95+11*I
21.72+64.12*I
-95.16-1.81*I
64.23+64.55*I
28.42-29.29*I
-49.25+7.87*I
44.98+79.62*I
69.8-1.24*I
61.99+37.01*I
72.43+56.88*I
Line: 2 [[-9.15+31.41*I +63.84-15.82*I -0.77-76.80*I -85.59+74.86*I +93.00-35.10*I -93.82+52.80*I +85.45+82.42*I +0.67-55.77*I -58.32+72.63*I -27.66-81.15*I]]
-9.15+31.41*I
63.84-15.82*I
-0.77-76.8*I
-85.59+74.86*I
93-35.1*I
-93.82+52.8*I
85.45+82.42*I
0.67-55.77*I
-58.32+72.63*I
-27.66-81.15*I
Line: 3 [[+87.97+9.03*I +7.05-74.91*I +27.60+65.89*I +49.81+25.08*I +44.33+77.00*I +93.27-7.74*I +61.62-5.01*I +99.33-82.80*I +8.83+62.96*I +7.45+73.70*I]]
87.97+9.03*I
7.05-74.91*I
27.6+65.89*I
49.81+25.08*I
44.33+77*I
93.27-7.74*I
61.62-5.01*I
99.33-82.8*I
8.83+62.96*I
7.45+73.7*I
Line: 4 [[+40.99-12.44*I +53.34+21.74*I +75.77-62.56*I +54.16-26.97*I -37.02-31.93*I +78.20-20.91*I +79.64+74.71*I +67.95-40.73*I +58.19+61.25*I +62.29-22.43*I]]
40.99-12.44*I
53.34+21.74*I
75.77-62.56*I
54.16-26.97*I
-37.02-31.93*I
78.2-20.91*I
79.64+74.71*I
67.95-40.73*I
58.19+61.25*I
62.29-22.43*I
Line: 5 [[+47.36-16.19*I +68.48-15.00*I +6.85+61.50*I -6.62+55.18*I +34.95-69.81*I -88.62-81.15*I +75.92-74.65*I +85.17-3.84*I -37.20-96.98*I +74.97+78.88*I]]
47.36-16.19*I
68.48-15*I
6.85+61.5*I
-6.62+55.18*I
34.95-69.81*I
-88.62-81.15*I
75.92-74.65*I
85.17-3.84*I
-37.2-96.98*I
74.97+78.88*I
Line: 6 [[+56.80+63.63*I +92.83-16.18*I -11.47+8.81*I +90.74+42.86*I +19.11-56.70*I -77.93-70.47*I +6.73+86.12*I +2.70-57.93*I +57.87+29.44*I +6.65-63.09*I]]
56.8+63.63*I
92.83-16.18*I
-11.47+8.81*I
90.74+42.86*I
19.11-56.7*I
-77.93-70.47*I
6.73+86.12*I
2.7-57.93*I
57.87+29.44*I
6.65-63.09*I
Line: 7 [[-35.35-70.67*I +8.08-21.82*I +86.72-93.82*I -28.96-24.69*I +68.73-15.36*I +52.85+94.65*I +85.07-84.04*I +9.98+29.56*I -78.01-81.23*I -10.67+13.68*I]]
-35.35-70.67*I
8.08-21.82*I
86.72-93.82*I
-28.96-24.69*I
68.73-15.36*I
52.85+94.65*I
85.07-84.04*I
9.98+29.56*I
-78.01-81.23*I
-10.67+13.68*I
Line: 8 [[+83.10-33.86*I +56.87+30.23*I -78.56+3.73*I +31.41+10.30*I +91.98+29.04*I -9.20+24.59*I +70.82-19.41*I +29.21+84.74*I +56.62+92.29*I +70.66-48.35*I]]
83.1-33.86*I
56.87+30.23*I
-78.56+3.73*I
31.41+10.3*I
91.98+29.04*I
-9.2+24.59*I
70.82-19.41*I
29.21+84.74*I
56.62+92.29*I
70.66-48.35*I
All done:
-1.95+11*I
21.72+64.12*I
-95.16-1.81*I
64.23+64.55*I
28.42-29.29*I
-49.25+7.87*I
44.98+79.62*I
69.8-1.24*I
61.99+37.01*I
72.43+56.88*I
-9.15+31.41*I
63.84-15.82*I
-0.77-76.8*I
-85.59+74.86*I
93-35.1*I
-93.82+52.8*I
85.45+82.42*I
0.67-55.77*I
-58.32+72.63*I
-27.66-81.15*I
87.97+9.03*I
7.05-74.91*I
27.6+65.89*I
49.81+25.08*I
44.33+77*I
93.27-7.74*I
61.62-5.01*I
99.33-82.8*I
8.83+62.96*I
7.45+73.7*I
40.99-12.44*I
53.34+21.74*I
75.77-62.56*I
54.16-26.97*I
-37.02-31.93*I
78.2-20.91*I
79.64+74.71*I
67.95-40.73*I
58.19+61.25*I
62.29-22.43*I
47.36-16.19*I
68.48-15*I
6.85+61.5*I
-6.62+55.18*I
34.95-69.81*I
-88.62-81.15*I
75.92-74.65*I
85.17-3.84*I
-37.2-96.98*I
74.97+78.88*I
56.8+63.63*I
92.83-16.18*I
-11.47+8.81*I
90.74+42.86*I
19.11-56.7*I
-77.93-70.47*I
6.73+86.12*I
2.7-57.93*I
57.87+29.44*I
6.65-63.09*I
-35.35-70.67*I
8.08-21.82*I
86.72-93.82*I
-28.96-24.69*I
68.73-15.36*I
52.85+94.65*I
85.07-84.04*I
9.98+29.56*I
-78.01-81.23*I
-10.67+13.68*I
83.1-33.86*I
56.87+30.23*I
-78.56+3.73*I
31.41+10.3*I
91.98+29.04*I
-9.2+24.59*I
70.82-19.41*I
29.21+84.74*I
56.62+92.29*I
70.66-48.35*I
The code would handle lines with any number of entries on a line (up to 128 in total because of the limit on the size of the array of complex numbers — but that can be fixed too.

unsorted double linked list corrupted Aborted (core dumped)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <time.h>
typedef char string [50];
typedef struct adresse{
int zip_code;
string city;
}
adresse Fr[27381996];// I will upload data to this table from the file
int main (){
int i=-1, line_nb=1;
int j=1;
double timing=0.0;//This is for calculating the timing
//These upcoming lines are for opening the file
FILE * France_adr;
France_adr=fopen("france.csv","r");
char adr[300];
for(line_nb=1;line_nb<10;line_nb++)
{
time_t begin= time(NULL);//Here I start the timing
while((!feof(France_adr))&& (i<line_nb))
{
fgets(adr,300,France_adr);
char* s = strdup(adr);
char* val = strsep(&s,","); /* This is because in the file
there are some data that I
don't want to use and they are separated with a comma*/
while(val!=NULL)
{
val=strsep(&s,",");
// This is also to sort the data I want to get into my
table
if(j==2 && i!=-1)
{
Fr[i].zip_code=atoi(val);
printf("%d | ",Fr[i].zip_code);
}
j++;
}
i++;
j=1;
printf("\n");
}
fclose(France_adr);
printf("\n\n");
time_t end = time(NULL);
duree += (double)(1000*(end-begin));
//This section is for writing the timing and number of lines into a new
file
FILE * donnee_t;
donnee_t=fopen("Affichage_Donnee_Courbe.csv","a");
fprintf(donnee_t,"\n %d,%f",i,duree);
fclose(donnee_t);
i=0;
}
return 0;
}
I am working on this project where I have to upload huge data from a file. So what I got do is to display those lines of data on the terminal and see how much it takes for it to be displayed, and eventually creating a curve that shows how the time evolves according to the number of lines displayed (So
I write the number of lines displayed and time it took it to be displayed in another file .CSV). And since the file has 27 million line of data I thought of doing a loop for how many lines I want to display every time, But the terminal shows me that this error. I hope I explained the problem very well and I hope I can have your help. enter image description here

My professor ran this code successfully, but I cannot. Seems to be an issue with the fopen() and the pointers

Edit: If it matters, I'm using Dev C++ with -std=c99 as an option.
My professor was able to run this code in class and successfully open a file that eventually reads the data into a linked list. When running the exact same code, my program abruptly exits despite the file being successfully opened.
All I'm trying to do is get this code to run. I've solved what he wants us to solve in my own example, but I can't figure out why his code doesn't run on my machine.
I did add in a puts("Success") line to verify the file has been opened, and I've gone through the methods it calls to see if I can find an error, but I cannot.
Here is the method with the issue (I'm assuming)
int ReadFileStoreInList(void)
{
FILE *cfPtr;
if ((cfPtr = fopen("Hertz-Homework-9-List.txt", "r")) !=NULL)
{
char make[TWELVE]={""}, model[TWELVE]={""}, size[TWELVE]={""}, color[TWELVE]={""}, power[TWELVE]={""};
char rented = 'A';
float daily_rate=0.0;
char dAilyRate[TWELVE];
fscanf(cfPtr, "%s%s%s%s%s%s", make, model, size, color, power, dAilyRate);
while (!feof(cfPtr))
{
fscanf(cfPtr, "%s%s%s%s%s%f", make, model, size, color, power, &daily_rate);
rented = 'A';
add_at_end(make, model, size, color, power, daily_rate, rented);
}
printScreenTitleAndHeaderForCars();
traverse_in_order();
}
else
{
puts("Input data file could not be opened, I have no new inventory of cars from headquarters\n\n\n");
}
fclose(cfPtr);
}
This calls traverse_in_order(); and printScreenTitleAndHeaderForCars();, which I will list below.
void traverse_in_order()
{
node *ptr;
if(start==NULL)
{
printf("list is empty\n");
return;
}
printScreenTitleAndHeaderForCars();
for(ptr=start; ptr!=NULL; ptr=(*ptr).next)
printf("%-12s%-12s%-12s%-12s%-12s%9.2f%12c\n", ptr->make, ptr->model, ptr->size, ptr->color, ptr->power, ptr->daily_rate, ptr->rented);
}
void printScreenTitleAndHeaderForCars()
{
system("Cls");
printf("%35s\n\n","Hertz Rental Cars");
printf("%79s\n","Avail");
printf("%-12s%-12s%-12s%-12s%-12s%-12s%8s\n", "Make", "Model", "Size", "Color", "Power", "Daily_Rate", "Rented");
for (int x=0; x< 7; x++)
printf("----------- ");
printf("\n");
}
In case the structure/header file was also needed:
#define TWELVE 12
typedef struct node_type
{
char make[TWELVE];
char model[TWELVE];
char size[TWELVE];
char color[TWELVE];
char power[TWELVE];
float daily_rate;
char rented;
struct node_type *next;
} node;
node *start=NULL;
int ReadFileStoreInList(void);
void add_at_beginning();
void add_at_end(char make[TWELVE], char model[TWELVE], char size[TWELVE], char color[TWELVE], char power[TWELVE], float daily_rate, char rented);
void add_after_element();
void add_before_element();
void traverse_in_order();
void traverse_in_reverse_order(node *);
void delete_at_beginning();
void delete_at_end();
void delete_after_element();
void delete_before_element();
void sort();
void doSomething(); // menu to ask operator what to do
void RentaCar();
void FindCarAndUpdateAsRented(char *modelSelected);
void ReturnCar();
void toTitleCase(char *aString);
void printScreenTitleAndHeaderForCars();
Requested add_at_end function:
void add_at_end(char make[TWELVE], char model[TWELVE], char size[TWELVE], char color[TWELVE], char power[TWELVE], float daily_rate, char rented)
{
node *ptr, *loc;
ptr = (node *) malloc(sizeof(node));
if(ptr==NULL)
{
printf("no space\n");
return;
}
strcpy((*ptr).make,make);
strcpy((*ptr).model,model);
strcpy((*ptr).size,size);
strcpy((*ptr).color,color);
strcpy((*ptr).power,power);
(*ptr).daily_rate = daily_rate;
(*ptr).rented = rented;
if(start==NULL)
{
start=ptr;
(*start).next=NULL;
}
else
{
loc = start;
while((*loc).next != NULL)
loc=(*loc).next;
(*loc).next=ptr;
(*ptr).next=NULL;
}
}
Interesting enough, if I rename this file to something that isn't correct, the proper printScreenTitleAndHeaderForCars() text executes and shows on screen. That's why I believe it has something to do with ReadFileStoreInList();
I've tried to debug this for a few hours now, but with the knowledge I've learned in class I just can not figure out why this doesn't run.
I expect the output to have the header information given from printScreenTitleAndHeaderForCars(), and then the data from the file I'm reading to appear on screen.
When the file is named improperly in my code, it runs this:
Hertz Rental Cars
Avail
Make Model Size Color Power Daily_Rate Rented
----------- ----------- ----------- ----------- ----------- ----------- -----------
list is empty
enter choice
1. Select Model and Rent
2. Select Model and Return
5. traverse in order
11. sort
12. exit
Where "list is empty" is situated, it should be populating the data from the text file and putting it there.
Instead, I just get:
--------------------------------
Process exited after 1.433 seconds with return value 3221225477
Press any key to continue . . .
I have a feeling this has to do with the way the pointers are written, but I'm struggling to understand how he could run the code and I couldn't.
Any knowledge as to why this might happen would be appreciated!
Edit: Text file contents:
make, model, size, color, power,daily rate.
Mazda,3,4-door,Black,4-Cyl,$99.73
Jeep,Cherokee,4-door,Blue,8-Cyl,$131.92
Buick,Regal,4-door,Purple,6-Cyl,$125.19
Fullsize,SUV,5-door,Brown,8-Cyl,$163.94
Chrysler,Pacifica,4-door,Green,6-Cyl,$127.49
Ford,Focus,2-door,Red,4-Cyl,$99.73
VW,Jetta,2-door,Orange,4-Cyl,$94.91
Chevrolet,Suburban,4-door,Yellow,8-Cyl,$204.92
Nissan,Pathfinder,4-door,White,6-Cyl,$145.11
Chevrolet,Spark,2-door,Teal,4-Cyl,$99.55
You concluded in comments that you thought the data file contents were to blame for your issue. You now having posted those, I can confirm that they are indeed a contributing factor. Imprudent details of your scanf format also contribute.
In the first place, the call for reading the header is dangerous:
fscanf(cfPtr, "%s%s%s%s%s%s", make, model, size, color, power, dAilyRate);
Since the data are just going to be discarded, there is no point in storing them. Moreover, it's not necessarily safe to assume that the header data will have characteristics matched to those of the associated data. It would be better to read and not assign the whole line:
fscanf(cfPtr, "%*[^\n]");
The * in the format says that the field directive is not to be assigned, only read. Overall, that reads (and ignores) everything up to but not including the first newline. That also allows you to get rid of the abominably-named dAilyRate variable.
Then there is the format for reading the actual data:
fscanf(cfPtr, "%s%s%s%s%s%f", make, model, size, color, power, &daily_rate);
It simply does not match the data. Specifically, the %s field descriptor skips leading whitespace and matches a whitespace-delimited string. Your data are comma-delimited, not whitespace-delimited except for line terminators. As a result, that scanf call will try to write a whole line's worth of data into each of the first five strings, thus overrunning each of their bounds. That's a plausible reason for a segfault.
What's more, the line read into daily_rate will fail, since the next data available at that point will be non-numeric. Yet even if the commas were changed to spaces, the rate data would still not be read correctly, because $ is not a valid part of a number. And that, in turn will throw off the reads for the second and subsequent lines.
The field overruns could have been avoided by specifying maximum field widths in the format. It would, moreover, be prudent to check the return value of scanf() to verify that all fields were read, as #Achal demonstrated in his answer, before relying on that data.
Here's a data file in a format compatible with the formats you're actually using:
make model size color power rate
Mazda 3 4-door Black 4-Cyl 99.73
Jeep Cherokee 4-door Blue 8-Cyl 131.92
Buick Regal 4-door Purple 6-Cyl 125.19
Fullsize SUV 5-door Brown 8-Cyl 163.94
Chrysler Pacifica 4-door Green 6-Cyl 127.49
Ford Focus 2-door Red 4-Cyl 99.73
VW Jetta 2-door Orange 4-Cyl 94.91
Chevrolet Suburban 4-door Yellow 8-Cyl 204.92
Nissan Pathfinder 4-door White 6-Cyl 145.11
Chevrolet Spark 2-door Teal 4-Cyl 99.55
And here's a safer way to read it:
#define STR_SIZE 12
char make[STR_SIZE]={""}, model[STR_SIZE]={""}, size[STR_SIZE]={""}, color[STR_SIZE]={""},
power[STR_SIZE]={""};
float daily_rate;
fscanf(cfPtr, "%*[^\n]");
while (fscanf(cfPtr, "%11s%11s%11s%11s%11s%f", make, model, size, color, power, &daily_rate) == 6) {
add_at_end(make, model, size, color, power, daily_rate, 'A');
}
The %11s fields will read up to 11 characters into your 12-character arrays, leaving room for the string terminator that fscanf() will append to each. This will still run into trouble if there is overlong data in the file, but it should not segfault.
I should say also that scanf is difficult to use safely and properly, and that there are other, better alternatives for parsing and consuming the data -- either in the original or in the modified format.
Here are few observation.
Firstly provide more readbility to your code by giving some meaningful macro name instead of TWELVE. For e.g #define NUMBER_OF_ITEMS 12
Secondly, In function definition the formal argument make[TWELVE] doesn't look good as you are passing char array & it decays to char*, so only char *make is enough.
This
void add_at_end(char make[TWELVE], char model[TWELVE], char size[TWELVE], char color[TWELVE], char power[TWELVE], float daily_rate, char rented) { }
can be replaced as
void add_at_end(char *make, char *model, char *size, char *color, char *power, float daily_rate, char rented) { }
And most importantly, this
fscanf(cfPtr, "%s%s%s%s%s%s", make, model, size, color, power, dAilyRate); /* Just Remove it */
just before
while (!feof(cfPtr))
creates an issue i.e that information you are not using, its getting overwritten by second fscanf() statement inside loop. Also do read Why is “while (!feof(file))” always wrong?
Sample code
void add_at_end(char *make, char *model, char *size, char *color, char *power, float daily_rate, char rented)
{
/* same code */
}
And
int ReadFileStoreInList(void)
{
FILE *cfPtr;
if ((cfPtr = fopen("input", "r")) !=NULL)
{
char make[TWELVE]={""}, model[TWELVE]={""}, size[TWELVE]={""}, color[TWELVE]={""}, power[TWELVE]={""};
char rented = 'A';
float daily_rate=0.0;
char dAilyRate[TWELVE];
while (fscanf(cfPtr, "%s%s%s%s%s%f", make, model, size, color, power, &daily_rate) == 6)
{
rented = 'A';
add_at_end(make, model, size, color, power, daily_rate, rented);
}
printScreenTitleAndHeaderForCars();
traverse_in_order();
}
else
{
puts("Input data file could not be opened, I have no new inventory of cars from headquarters\n\n\n");
return 0; /* in case of fopen failed */
}
fclose(cfPtr);
}

Searching a particular string in a large file

I am making program in C which can search for a specific string in a large .txt file and count it and then print it out. But it seems that something have go wrong, cause the output of my program is different from that of the two text editor. According to the text editor, there are totally 3000 words,in this case I search for the word "make", in that .txt file. But the output of my program is just 2970.
I cannot find out the problem of my program. So I am curios about how could a text editor search for a specific string so accurately? How do people implement that? Can any people show me some code in C?
To make things clear: that is a large .txt file, 20M or so, containing lots of characters. So I think it's not so good to read it into memory all at once. I have implement my program by splitting my program in to pieces and then scan all of those for parsing. However, it fail some way.
Maybe I should put the code here. Wait a minute please.
The code is kinda long, 70 lines or so. I have put it on my github, if you have any interest, please help. https://github.com/walkerlala/searchText
note that the only related file is wordCount.c and testfile.txt which goes like:
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
char arr[51];
int flag=0;
int flag2=0;
int flag3=0;
int flag4=0;
int pieceCount(FILE*);
int main()
{
//the file in which I want to search the word is testfile.txt
//I have formatted the file so that it contain no newlins any more
FILE* fs=fopen("testfile.txt","r");
int n=pieceCount(fs);
printf("%d\n",n);
rewind(fs); //refresh the file...
static bool endOfPiece1=false,endOfPiece2=false,endOfPiece3=false;
bool begOfPiece1,begOfPiece2,begOfPiece3;
for(int start=0;start<n;++start){
fgets(arr,sizeof(arr),fs);
for(int i=0;i<=46;++i){
if((arr[i]=='M'||arr[i]=='m')&&(arr[i+1]=='A'||arr[i+1]=='a')&&(arr[i+2]=='K'||arr[i+2]=='k')&&(arr[i+3]=='E'||arr[i+3]=='e')){
flag+=1;
//continue;
}
}
//check the border
begOfPiece1=((arr[1]=='e'||arr[1]=='E'));
if(begOfPiece1==true&&endOfPiece1==true)
flag2+=1;
endOfPiece1=((arr[47]=='m'||arr[47]=='M')&&(arr[48]=='a'||arr[48]=='A')&&(arr[49]=='k'||arr[49]=='K'));
begOfPiece2=((arr[1]=='k'||arr[1]=='K')&&(arr[2]=='e'||arr[2]=='E'));
if(begOfPiece2==true&&endOfPiece2==true)
flag3+=1;
endOfPiece2=((arr[48]=='m'||arr[48]=='M')&&(arr[49]=='a'||arr[49]=='A'));
begOfPiece3=((arr[1]=='a'||arr[1]=='A')&&(arr[2]=='k'||arr[2]=='K')&&(arr[3]=='e'||arr[3]=='E'));
if(begOfPiece3==true&&endOfPiece3==true)
flag4+=1;
endOfPiece3=(arr[49]=='m'||arr[49]=='M');
}
printf("%d\n%d\n%d\n%d\n",flag,flag2,flag3,flag4);
getchar();
return 0;
}
//the function counts how many pieces have I split the file into
int pieceCount(FILE* file){
static int count=0;
char arr2[51]={'\0'};
while(fgets(arr2,sizeof(arr),file)){
count+=1;
continue;
}
return count;
}
You can do this quite simply just by having a rolling buffer. You don't need to break the file into sections.
#include <stdio.h>
#include <string.h>
int main(void) {
char buff [4]; // word buffer
int count = 0; // occurrences
FILE* fs=fopen("test.txt","r"); // open the file
if (fs != NULL) { // if the file opened
if (4 == fread(buff, 1, 4, fs)) { // fill the buffer
do { // if it worked
if (strnicmp(buff, "make", 4) == 0) // check for target word
count++; // tally
memmove(buff, buff+1, 3); // shift the buffer down
} while (1 == fread(buff+3, 1, 1, fs)); // fill the last position
} // end of file
fclose(fs); // close the file
}
printf("%d\n", count); // report the result
return 0;
}
For simplicity I stopped short of making the search word "softer" and allocating the correct buffer and various sizes, since that wasn't in the question. And I have to leave something for OP to do.

fread returns no data in my buffer in spite of saying it read 4096 bytes

I'm porting some C code that loads sprites from files containing multiple bitmaps. Basically the code fopens the file, fgetcs some header info, then freads the bitmap data. I can see that the fgetcs are returning proper data, but the outcome of the fread is null. Here's the code - fname does exist, the path is correct, fil is non-zero, num is the number of sprites in the file (encoded into the header, little-endian), pak is an array of sprites, sprite is a typedef of width, height and bits, and new_sprite inits one for you.
FILE *fil;
uint8 *buffu;
uint8 read;
int32 x,num;
int32 w,h,c;
fil = fopen(fname, "rb");
if (!fil) return NULL;
num = fgetc(fil);
num += fgetc(fil)*256;
if (num > max) max = num;
for (x=0;x<max;x++) {
// header
w=fgetc(fil);
w+=fgetc(fil)*256;
h=fgetc(fil);
h+=fgetc(fil)*256;
fgetc(fil); // stuff we don't use
fgetc(fil);
fgetc(fil);
fgetc(fil);
// body
buffu = (uint8*)malloc(w * h);
read=fread(buffu,1,w*h,fil);
pak->spr[x]=new_sprite(w,h);
memcpy(pak->spr[x]->data, buffu, w*h);
// done
free(buffu);
}
I've stepped through this code line by line, and I can see that w and h are getting set up properly, and read=4096, which is the right number of bits. However, buffer is "" after the fread, so of course memcpy does nothing useful and my pak is filled with empty sprites.
My apologies for what is surely a totally noob question, but I normally use Cocoa so this pure-C file handling is new to me. I looked all over for examples of fread, and they all look like the one here - which apparently works fine on Win32.
Since fgetc seems to work, you could try this as a test
int each;
int byte;
//body
buffu = malloc(w * h);
for (each = 0; each < w*h; each++) {
byte = fgetc(fil);
if ( byte == EOF) {
printf("End of file\n");
break;
}
buffu[each] = (uint8)byte;
printf ("byte: %d each: %d\n", byte, each);
}
pak->spr[x]=new_sprite(w,h);
memcpy(pak->spr[x]->data, buffu, w*h);
// done
You say:
However, buffer is "" after the fread, so of course memcpy does nothing useful
But that is not true at all. memcpy() is not a string function, it will copy the requested number of bytes. Every time. If that isn't "useful", then something else is wrong.
Your buffer, when treated as a string (which it is not, it's a bunch of binary data) will look like an empty string if the first byte happens to be 0. The remaining 4095 bytes can be whatever, to C's string printing functions it will look "empty".

Resources