C Transforming array into string using sprintf - c

I have scanned "ABCDEFGHIJK" with fscanf into a char array[26]. Then I got "ABCDEFGHIJK" using "for" into another array[11]. Now I need to get to an "ABCDEFGHIJK.mp4" array[15] in order to feed that filename into a rename function.
I don't know much about C programming besides printf, scanf, for and while.
sprintf(filename, "%c%c%c%c%c%c%c%c%c%c%c.mp4", codigo[0], codigo[1], codigo[2], codigo[3], codigo[4], codigo[5], codigo[6], codigo[7], codigo[8], codigo[9], codigo[10]);
This code above seems to work, but I wonder if there is a simpler way (especially for bigger arrays)?
Clarification: I have a txt file, formatted with these containing the filenames without extension and the human filename. I'm trying to make a program that will rename these files to the correct name, as they are from a backup that failed.
EDIT: Here is the full program. I renamed the variables to make more sense, so "codigo" is now "idcode".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int i, j, k;
char value1[26], value2[70], idcode[11], filename[16], fullname[64], filenamestring[16], fullnamestring[64];
// Opening file.
FILE *nomes;
nomes = fopen("/Users/EA/Desktop/Songs/backup.txt", "rt");
if(nomes == NULL)
{
printf("Erro ao abrir backup.txt");
exit(1);
}
// Skipping beggining of file until first value.
for(i=0; i<10; i++)
{
fscanf(nomes, "%*s");
}
// Reading first value, and repetition.
while(fscanf(nomes, "%s", value1) == 1)
{
j = k = 0;
// Extracting idcode from value1.
for(i=7; i<18; i++)
{
idcode[j] = value1[i];
j++;
}
// Filling the complete filename.
sprintf(filename, "%.*s.mp4", 11, idcode);
// Reading second value, the "human" filename.
fscanf(nomes, "\n%[^\n]", value2);
for(i=6; i<70; i++)
{
fullname[k] = value2[i];
k++;
}
// Transforming filenames into strings for rename function.
strncpy(filenamestring, filename, 16);
strncpy(fullnamestring, fullname, 64);
// Renaming the files.
rename(filename, fullname);
// Skipping useless data before the next cycle.
for(i=0; i<9; i++)
{
fscanf(nomes, "%*s");
}
}
// Closing file and ending program.
fclose(nomes);
return(0);
}

It looks like you got an array of char's.
You can simply do:
sprintf(filename, "%.*s.mp4", 11, codigo)
You can read more about the %.*s specifier in this question.

If you just want to append the format ".mp4" to the end of the string the easiest way to do that is just:
strcat(filename,".mp4");
after you printed the name without the ".mp4" into it.
If you really want to use sprintf then i think this should suffice:
sprintf(filename,"%s.mp4", codigo);
Also,if you want your string to be bigger and not fixed in size you can put "\0" at the end of it(this might not work if you try to use the strings in other programming languages but c) with strcat as above,or you can do this:
memset(&filename, 0, sizeof(filename));

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.

Bubblesort Using Values Read From File In C

I'm new to C programming language and I'm having a really difficult time trying to do this:
I have a file .txt created by my program that store the leaderboard of the 2048 game that I'm doing, and I think that the easiest way to make the leaderboard is by appending the result to the end of the file and than doing a bubble sort, but I can't find the correct value (score) of the first place to compare with the next place, and so on.
Here is my code:
FILE* ptr;
prt = fopen("Placar.txt", "a");
if(ptr == NULL)
{
printf("Error!");
}
fclose(ptr);
ptr = fopen("Placar.txt", "r");
int ch, lines = 0, aux;
char line[150];
while(!feof(ptr))
{
ch = fgetc(ptr);
if (ch == '\n')
{
lines++;
}
}
fclose(ptr);
ptr = fopen("Placar.txt", "a");
fprintf(ptr, "%d: Name: %s - Score: %d - Movements: %d\n", lines+1, name, score, movements);
fclose(ptr);
// bubble sort
ptr = fopen("Placar.txt", "r+");
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
while (!feof(ptr))
{
fgets(line, 150, ptr);
if (strstr(linha, "Score: ") != NULL)
{
// dont know how to do
}
}
}
}
fclose(ptr);
// TODO: delete the 11th line to make the top 10 only
If you think that I'm overcomplicating this, let me know how would you do.
Thanks for the help.
I think that the easiest way to make the leaderboard is by appending the result to the end of the file and than doing a bubble sort
I don't think that's easiest at all. It's especially bad if, as appears to be the case, you have in mind to use the file as your workspace instead of reading the contents into memory, sorting there, and then writing the results back out.
If you think that I'm overcomplicating this, let me know how would you do.
Consider this alternative:
open the high-score file and a temporary file
read scores from the original file one by one and write them to the temp file, until you find the first that is less than the new score you are recording (or reach the end of the file)
write the new score to the temp file
copy the rest of the scores from the original file to the temp file
close both files and replace the original with the temp file.
That involves at most all the same reading, at most all the same writing, and no sorting except for just inserting the new score at the correct place in the sequence. If you like, you can consider it a variation on Insertion Sort. As a bonus, it also has the same, minimal, storage requirements no matter how many scores there are, and therefore does not require any dynamic memory allocation.

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.

Using a function to read in a file

I have the code below which compiles fine in xcode, but when I take it across to Microsoft Visual studio I get a bunch of errors.
void openfile(int mapArray[MAX_HEIGHT][MAX_WIDTH], int *interest, int *dimension1, int *dimension2)
{
int counter = 0;
char buffer;
int rowss, colss;
*interest = 0;
FILE *f;
f = fopen(FILENAME, "r");
if (f==NULL) {
printf("Map file could not be opened");
return 0;
}
// create char array the dimensions of the map
fscanf(f, "%d %d" , dimension1, dimension2 );
// printf("%d %d\n" , dimensions[0], dimensions[1]);
// Reads the spaces at the end of the line till the map starts
buffer=fgetc(f);
while (buffer!='*') {
buffer=fgetc(f);
}
// Read the txt file and print it out while storing it in a char array
while (buffer!=EOF) {
mapArray[rowss][colss]=buffer;
colss++;
// Count up the points of interest
if (((buffer>64)&&(buffer<90))||(buffer=='#') ) {
counter++;
}
// resets column counter to zero after newline
if (buffer=='\n') {
colss=0;
rowss++;
}
buffer=fgetc(f);
}
// Closes the file
fclose(f);
*interest=counter;
}
Which parts are creating all the errors?
I get this list of errors when attempting to compile
Thanks in advance.
I see a few immediate problems. First, you're not initialising rowss or colss before you use them, hence they could contain any value.
Second, fgetc() returns an int so that you can detect end of file. By using a char to hold the return value, you're breaking the contract with the standard library.
Thirdly, you return a 0 if the filename couldn't be opened, despite the fact that the function is specified to return void (ie, nothing).
No doubt those are three of the errors the compiler picked up on, there may be others, and you should probably post the error list with your question for a more exhaustive analysis.

Why does my program read an extra structure?

I'm making a small console-based rpg, to brush up on my programming skills.
I am using structures to store character data. Things like their HP, Strength, perhaps Inventory down the road. One of the key things I need to be able to do is load and save characters. Which means reading and saving structures.
Right now I'm just saving and loading a structure with first name and last name, and attempting to read it properly.
Here is my code for creating a character:
void createCharacter()
{
char namebuf[20];
printf("First Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].fname,namebuf);
printf("Last Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].lname,namebuf);
/*Character created, now save */
saveCharacter(party[nMember]);
printf("\n\n");
loadCharacter();
}
And here is the saveCharacter function:
void saveCharacter(character party)
{
FILE *fp;
fp = fopen("data","a");
fwrite(&party,sizeof(party),1,fp);
fclose(fp);
}
and the loadCharacter function
void loadCharacter()
{
FILE *fp;
character tempParty[50];
int loop = 0;
int count = 1;
int read = 2;
fp= fopen("data","r");
while(read != 0)
{
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
}
fclose(fp);
}
So the expected result of the program is that I input a name and last name such as 'John Doe', and it gets appended to the data file. Then it is read in, maybe something like
1. Jane Doe
2. John Doe
and the program ends.
However, my output seems to add one more blank structure to the end.
1. Jane Doe
2. John Doe
3.
I'd like to know why this is. Keep in mind I'm reading the file until fread returns a 0 to signify it's hit the EOF.
Thanks :)
Change your loop:
while( fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp) )
{
// other stuff
}
Whenever you write file reading code ask yourself this question - "what happens if I read an empty file?"
You have an algorithmic problem in your loop, change it to:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
while(read != 0)
{
//read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
}
There are ways to ged rid of the double fread but first get it working and make sure you understand the flow.
Here:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
You are not checking whether the read was successful (the return value of fread()).
while( 1==fread(&tempParty[loop],sizeof*tempParty,1,fp) )
{
/* do anything */
}
is the correct way.
use fopen("data","rb")
instead of fopen("data","r") which is equivalent to fopen("data","rt")
You've got the answer to your immediate question but it's worth pointing out that blindly writing and reading whole structures is not a good plan.
Structure layouts can and do change depending on the compiler you use, the version of that compiler and even with the exact compiler flags used. Any change here will break your ability to read files saved with a different version.
If you have ambitions of supporting multiple platforms issues like endianness also come into play.
And then there's what happens if you add elements to your structure in later versions ...
For robustness you need to think about defining your file format independently of your code and having your save and load functions handle serialising and de-serialising to and from this format.

Resources