My main objective here is to make use of fscanf() to take in each word from my file and store it into an array location. As it stands, I loop through the file setting each word to a location in wordList[]. I can print out the values as they are put into the array and each seems to be placed correctly. But after the loop, when I attempt to print only one of the values (simply checking that everything went as it should) I get a weird output. When printing the string contained in wordList[5], it prints the first character of every word after location [5], and prints the last word that was collected.
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void readFile (FILE *fPtr, char *fileName) {
FILE *newFilePtr;
char wordList[1000];
int i = 0;
newFilePtr = fopen(strcat(fileName, ".out"), "w"); // Blank document created under same file name, but with ".out"
while(fscanf(fPtr, "%s", &wordList[i]) == 1) { // Read in strings from main file into wordList
printf("%s\n", &wordList[i]);
++i;
if (i > 10) // KEEP OUTPUT SHORT FOR STACK OVERFLOW QUESTION
break;
}
printf("%s\n", &wordList[5]); // PRINTS WILD VALUE AT POSITION 5
fclose(newFilePtr);
}
int main (int argc, char *argv[]) {
int lineSize;
char *fileName = argv[2]; // Store name of file for future operations
FILE *fPtr;
if (argc != 3) {
fprintf(stderr, "%s", "ERROR: Incorrect arguments. Please input a line size and a file.\n");
return;
}
lineSize = atol(argv[1]); // Convert string to it's integer equivalent
if (lineSize < 25 || lineSize > 100) {
fprintf(stderr, "%s", "ERROR: Line size not within range.\n");
return;
}
if (fPtr = fopen(fileName, "r")) { // If the file exists, open it for reading
readFile(fPtr, fileName);
puts("FILE OPENED SUCCESS");
fclose(fPtr);
} else {
fprintf(stderr, "%s", "ERROR: File could not be opened.\n");
return;
}
return;
}
And my current output (constrained to just the first 10 values to keep it short):
Mason–Dixon
Line
(or
Mason
and
Dixon's
Line)
was
surveyed
between
1763
DLwsb1763 // Should print "Dixon's" (the string at location 5)
FILE OPENED SUCCESS
The creation of the new file at line 11 is for later use when the file is formatted. For now, i'm only concerned with properly scanning in the values from the original file.
Related
I am trying to write struct to file. I have done the part where I defined struct I read text from file and then I saved it in struct now I am on a point where I want to make change in struct: students[i].name and then I want the change to be reflected (write) in file but it has invalid encoding.
file.txt has this structure:
U,Virat Kohli,Virat Kohli,
U,Serena Williams,Virat Kohli,
G,Wayne Gretzky,Virat Kohli,
U,Virat Kohli,Virat Kohli,
U,Serena Williams,Virat Kohli,
G,Wayne Gretzky,Virat Kohli,
Here is my code:
#include <stdio.h>
#include <string.h>
typedef struct
{
// members for the student's type, name, surname
char type;
char name[50];
char surname[50];
} Student;
int main(void)
{
// for comparing strcmp
int result;
// file pointer variable for accessing the file
FILE *file;
// attempt to open file.txt in read mode to read the file contents
file = fopen("file.txt", "r");
// if the file failed to open, exit with an error message and status
if (file == NULL)
{
printf("Error opening file.\n");
return 1;
}
// array of structs for storing the Student data from the file
Student students[100];
// read will be used to ensure each line/record is read correctly
int read = 0;
// records will keep track of the number of Student records read from the file
int records = 0;
// read all records from the file and store them into the students array
while (fscanf(file, " %c , %49[^,], %49[^,],", &students[records].type, students[records].name, students[records].surname) == 3)
{
// if fscanf read 3 values from the file then we've successfully read
records++;
// if there was an error reading from the file exit with an error message
// and status
if (ferror(file))
{
printf("Error reading file.\n");
return 1;
}
}
// close the file as we are done working with it
fclose(file);
// print out the number of records read
printf("\n%d records read.\n\n", records);
// print out each of the records that was read
for (int i = 0; i < records; i++)
printf("%c %s %s\n",
students[i].type,
students[i].name,
students[i].surname);
printf("\n");
// change first record's name to Elena Heis
for (int i = 0; i < 1; i++)
{
if (students[i].name == students[i].name)
{
printf("%s\n",
students[i].name);
strcpy(students[i].name, "Elena Heis");
printf("%s\n",
students[i].name);
}
}
// write changes to file
file = fopen("file.txt", "wb");
if (file != NULL)
{
fwrite(students, sizeof(Student), 1, file);
fclose(file);
}
return 0;
}
After write file has broken encoding like this
It should be
Your code is clean and your format string is almost perfect, yet parsing the csv file (or any file in general) with fscanf() is not recommended as it is very difficult to recover from errors and newlines are mostly indistinguishable from other white space characters. In particular, the \n at the end of the format string will match any possibly empty sequence of white space characters.
Testing ferror() and feof() as you do seems fine but insufficient to ensure reliable parsing: if fscanf() returns a short code, for example because of an empty field, parsing will continue from the middle of the offending line and neither ferror() nor feof() will cause the loop to end.
You should instead read one line at a time with fgets() and use sscanf() to parse the line.
Also note these remarks:
the csv file does not seem to contain name and surname fields but rather the full names of opponents.
this file seems to have trailing , after the third field. If this is expected, the format string ensuring record validity should be changed to "%c,%49[^,],%49[^,\n]%1[,\n]"
you should check that records < 100 to avoid a buffer overflow.
the test if (students[i].name == students[i].name) is useless and always true. No test is needed to change the name of the first student.
you cannot write the text file with fwrite(students, sizeof(Student), 1, file), you should instead use fprintf as for the output to the terminal.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <string.h>
typedef struct
{
// members for the student's type, name, surname
char type;
char name[50];
char surname[50];
} Student;
int main(void)
{
// file pointer variable for accessing the file
FILE *file;
// attempt to open file.txt in read mode to read the file contents
file = fopen("file.txt", "r");
// if the file failed to open, exit with an error message and status
if (file == NULL)
{
fprintf(stderr, "Error opening file %s for reading: %s\n", "file.txt", strerror(errno));
return 1;
}
// array of structs for storing the Student data from the file
Student students[100];
// length of the students array
int nrecords = sizeof(students) / sizeof(*students);
// buffer to read one line at a time
char buffer[256];
// records will keep track of the number of Student records read from the file
int records = 0;
// read all records from the file and store them into the students array
while (records < nrecords && fgets(buffer, sizeof buffer, file))
{
// Read a line/record from the file
// if it was able to read successfully which we expect read will be 3
char newline[3]; // for characters at end of line: `,\n` or `\n`
char extra; // to ensure no more characters are present
// there are 5 conversion specifiers, but sscanf should parse
// exactly 4 fields, including the trailing `,` and the newline
int read = sscanf(buffer,
"%c,%49[^,],%49[^,\n]%2[,\n]%c",
&students[records].type,
students[records].name,
students[records].surname,
newline, &extra);
// if fscanf read 3 values and a newline from the file then we've successfully read
// in another record
if (read == 4) {
records++;
} else {
fprintf(stderr, "invalid record: %s", buffer);
}
}
// if there was an error reading from the file exit with an error message
// and status
if (ferror(file))
{
fprintf(stderr, "Error reading file: %s\n", strerror(errno));
fclose(file);
return 1;
}
// close the file as we are done working with it
fclose(file);
// print out the number of records read
printf("\n%d records read.\n\n", records);
// print out each of the records that was read
for (int i = 0; i < records; i++)
{
printf("%c %s %s\n",
students[i].type,
students[i].name,
students[i].surname);
}
printf("\n");
// change first record's name to Elena Heis
strcpy(students[0].name, "Elena Heis");
printf("%s\n", students[0].name);
// write changes to file
file = fopen("file.txt", "w");
if (file == NULL)
{
fprintf(stderr, "Error opening file %s for writing: %s\n", "file.txt", strerror(errno));
return 1;
}
// print out each of the records that was read
for (int i = 0; i < records; i++)
{
fprintf(file, "%c,%s,%s,\n",
students[i].type,
students[i].name,
students[i].surname);
}
fclose(file);
return 0;
}
For example I have a text file includes "I'm having great day!", I want to count each character and word in this file.
in the example "there are 3 a, 1 m" etc.
I'm new at C and know how to open a file, how can find a specific char or word in file but couldn't figure this out. Can you help me pls.
The first thing you need to learn is how to open and process a file one character at a time. You can do this with a program like:
#include <stdio.h>
int main(int argc, char *argv[]) {
// Must provide one argument, the file to process.
if (argc != 2) {
fprintf(stderr, "Usage: myprog <inputFileName>\n");
return 1;
}
// Try to open the file.
FILE *inFile = fopen(argv[1], "r");
if (inFile == NULL) {
fprintf(stderr, "Cannot open '%s'\n", argv[1]);
return 1;
}
// Process file, character by character, until finished.
int ch;
while ((ch = fgetc(inFile)) != EOF) {
putchar(ch); // <accumulate>
}
// Close file and exit.
fclose(inFile);
// <output>
return 0;
}
Then it's a matter of changing the putchar call into whatever you need to do (accumulating character counts) and outputting that information before you exit from the main function.
In this code I opened my files in my open_file function. Then the process_file function needs to copy the text from my in file and Copy it to an out file. Right now it produces a new file but it is blank. It does not give me any error messages. I do not know what is wrong.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_LEN 100
FILE* open_file(char prompt[], char mode[]);
FILE* process_file(FILE* in, FILE* out);
int main(int argc, const char * argv[]) {
FILE* in = NULL;
FILE* out = NULL;
printf("MAD-LIBS Text Processor\n");
printf("The Program will open a mad-libs file, ask you to fill various words, and produce a funny story.\n");
open_file("Enter mad-lib file name:\n", "r");
open_file("Enter file name for resulting story:\n", "w");
process_file(in, out);
fclose(in);
fclose(out);
return 0;
}
/* open_file = prompts user for file name & and attempts to open it, if it fails it prompts the user again. */
FILE* open_file(char prompt [], char mode[]) {
char filename[255];
FILE* in;
do {
printf("%s", prompt);
scanf("%s", filename);
in = fopen(filename, mode);
if (in == NULL) {
printf("Unable to open file: %s. Try Again!\n", filename);
}
} while(in == NULL);
return in;
}
/* process_file = processes entire input file and writes it to output file */
FILE* process_file(FILE* in, FILE* out) {
char content[MAX_LEN];
char NewContent[MAX_LEN];
//gets whats in file in
while(fgets(content, content[MAX_LEN], in) != NULL) {
fputs (content, stdout);
strcat(NewContent, content);
}
// copies it
while (fgets(content, content[MAX_LEN], in) != NULL) {
fprintf(out, "%s", content);
}
printf("Successfully copied file\n");
return in;
}
You never assign the FILE* from open_file function to your variable, so it never gets processed.
in = open_file("Enter mad-lib file name:\n", "r");
out = open_file("Enter file name for resulting story:\n", "w");
You are not storing the FILE pointers that open_file is returning, so in
and out remain uninitialized.
You have to do:
in = open_file("Enter mad-lib file name:\n", "r");
out = open_file("Enter file name for resulting story:\n", "w");
process_file(in, out);
Also your process_file is wrong. NewContent is not initialized, when you do
strcat(NewContent, content);
this yields undefined behaviour. Declare NewContent like this:
char NewContent[MAX_LEN] = { 0 };
so that it is properly \0-terminated.
Also depending on the size of the file you are copying, MAX_LEN might not be
long enough to hold the whole file. In that case you would overflow the buffer.
It would be better not to use NewContent in the first place and write to out
in the same reading loop:
FILE* process_file(FILE* in, FILE* out) {
char content[MAX_LEN];
//gets whats in file in
while(fgets(content, MAX_LEN, in) != NULL) { //<- your fgets was wrong
fputs (content, stdout);
fprintf(out, "%s", content); // or fputs(content, out);
}
printf("Successfully copied file\n");
return in;
}
And you were calling fgets incorrectly (look at my corrected code)
Also bear in mind, that you did have 2 loop doing while(fgets(...) != NULL.
Well, the first loop ends, that's because fgets returns NULL, most likely
because the whole file was read or there was an I/O error. In either case
subsequent calls of fgets will return NULL as well, so your second loop
would not even be executed at all.
I have created a function that takes as a parameter the name of a source file, the name of a destination file and the beginning and end lines of the source file lines that will be copied to the destination file, like the example below. All I want to do is to input the lines that I want to copy to the other text file like the example below:
The code I show you just "reads" the content of the one text file and "writes" another one. I want to "write" specific lines that the user gives, not the whole text file
Inputs by the user:
Source_file.txt //the file that the destination file will read from
destination_file.txt //the new file that the program has written
2 3 // the lines that it will print to the destination file: 2-3
Source_file.txt:
1
2
3
4
5
6
destination_file.txt
2
3
code:
#include <stdio.h>
#include <stdlib.h>
void cp(char source_file[], char destination_file[], int lines_copy) {
char ch;
FILE *source, *destination;
source = fopen(source_file, "r");
if (source == NULL) {
printf("File name not found, make sure the source file exists and is ending at .txt\n");
exit(EXIT_FAILURE);
}
destination = fopen(destination_file, "w");
if (destination == NULL) {
fclose(source);
printf("Press any key to exit...\n");
exit(EXIT_FAILURE);
}
while ((ch = fgetc(source)) != EOF)
fputc(ch, destination);
printf("Copied lines %d from %s to %s \n",
lines_copy, source_file, destination_file, ".txt");
fclose(source);
fclose(destination);
}
int main() {
char s[20];
char d[20];
int lines;
printf("-Enter the name of the source file ending in .txt\n"
"-Enter the name of the destination file ending in .txt\n"
"-Enter the number of lines you want to copy\n\n");
printf(">subcopy.o ");
gets(s);
printf("destination file-> ");
gets(d);
printf("Lines: ");
scanf("%d", &lines);
cp(s, d, lines);
return 0;
}
In cp(), in order to select the lines to keep, you have to know their position in the input-file. Thus, you need to count lines.
Using fgets instead of fgetc will allow you to count the lines.
On the other hand, if I wanted to select lines 3 and 7 to 12 in a file, I'd use:
sed -n -e "3p;7,12p" < input.txt > output.txt
this is a very simple solution, let's say you know that the maximun length of a line will be 100 characters for simplicity (if a line is longer than 100 characters only the first 100 will be taken)
at the top (outside main) you can write
#ifndef MAX_LINE_SIZE
#define MAX_LINE_SIZE 100
#endif
i know many people don't like this but i think in this case it makes the code more elegant and easier to change if you need to modify the maximum line size.
to print only the wanted lines you can do something like this
char line[MAX_LINE_SIZE];
int count = 0;
while (fgets(line, MAX_LINE_SIZE, source)){
count++;
if (3 <= count && count <= 5){
fputs(line, destination);
}
}
The while loop will end when EOF is reched because fgets returns NULL.
P.S. there could be some slight errors here and there since i wrote it pretty fast and going by memory but in general it should work.
There are some problems in your program:
Do not use gets(), it may cause buffer overflows.
Always use type int to store the return value of fgetc() in order to distinguish EOF from regular byte values.
You pass an extra argument ".txt" to printf(). It will be ignored but should be removed nonetheless.
To copy a range of lines from source to destination, you can just modify your function this way:
#include <stdio.h>
#include <string.h>
#include <errno.h>
void cp(char source_file[], char destination_file[], int start_line, int end_line) {
int ch;
int line = 1, lines_copied;
FILE *source, *destination;
source = fopen(source_file, "r");
if (source == NULL) {
printf("Cannot open input file %s: %s\n",
source_file, strerror(errno));
exit(EXIT_FAILURE);
}
destination = fopen(destination_file, "w");
if (destination == NULL) {
printf("Cannot open output file %s: %s\n",
destination_file, strerror(errno));
fclose(source);
exit(EXIT_FAILURE);
}
while ((ch = fgetc(source)) != EOF) {
if (line >= start_line && line <= end_line) {
fputc(ch, destination);
}
if (ch == '\n') {
line++;
}
}
lines_copied = 0;
if (line > start_line) {
if (line >= end_line) {
lines_copied = end_line - start_line + 1;
} else {
lines_copied = line - start_line + 1;
}
}
printf("Copied lines %d from %s to %s\n",
lines_copy, source_file, destination_file);
fclose(source);
fclose(destination);
}
int main() {
char source_file[80];
char destination_file[80];
int start_line, end_line;
printf("-Enter the name of the source file ending in .txt\n"
"-Enter the name of the destination file ending in .txt\n"
"-Enter the start and end line\n\n");
printf(">subcopy.o ");
if (scanf("%79s", source_file) != 1) {
return 1;
}
printf("destination file-> ");
if (scanf("%79s", destination_file) != 1) {
return 1;
}
printf("Start and end lines: ");
if (scanf("%d %d", &start_line, &end_line) != 2) {
return 1;
}
cp(source_file, destination_file, start_line, end_line);
return 0;
}
I have a file which contains the files names for every file in a directory. I am trying to open that file, read the file names from it and then open each file. However, I cannot get it to open the files. I have it printing the word it is reading and know it is reading correctly; however, it will not open the file. Any suggestions? My program is below.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
FILE *in;
FILE *in2;
char inName[] = "inputfile.txt";
char *inName2;
inName2 = malloc(36 * sizeof (char));
char inPhrase[100];
if (( in = fopen(inName, "r")) == NULL )
{
printf("Can't open %s for reading.\n", inName);
return 2;
}
else
{
fgets(inName2, 36, in);
}
if (( in = fopen(inName2, "r")) == NULL )
{
printf("Can't open %s for reading. \n", inName2);
}
else
{
fgets(inPhrase, 100, in2);
printf("%s\n", inPhrase);
}
fclose(in);
fclose(in2);
return 0;
}
You have one outright typo and one mistake in your code. The line if (( in = fopen(inName2, "r")) == NULL ) should open in2 instead: if (( in2 = fopen(inName2, "r")) == NULL ). Your error message almost certainly reads something like this:
Can't open test_file.txt
for reading
Notice the newline that fgets always reads in for you. You should trim the line somehow. There are a few options available:
If your last line is guaranteed to be newline terminated, you can just remove the last character from each line: strchr(inName2, '\0')[-1] = '\0';.
You can trim the whitespace from the end of each line.
You can delete the last character only if it is \n (or possibly two characters, \r\n on Windows)
Final note: you should always post your error messages. If you were clever enough to interpret it properly in the first place, you would not be posting here, so don't expect us to take your word for where the program failed.
Do it this way
#include <stdio.h>
#include <stdlib.h>
int main() {
char inName[] = "inputfile.txt", * inName2;
FILE * in = fopen(inName, "r"), * in2;
char inPhrase[100];
size_t len;
// Check whether file opened correctly or display error
if (in == NULL) { perror(inName); return 1; }
// Read file line by line
while (getline(&inName2, &len, in) != -1) {
// Check if file opens otherwise go to next file
if ((in2 = fopen(inName2, "r")) == NULL) { perror(inName2); continue; }
// Read 100 chars from each file and display
fgets(inPhrase, 100, in2);
printf("%s\n", inPhrase);
fclose(in2);
}
fclose(in);
return 0;
}