I tried to read and print words from a text file, but the program somehow closed itself.
int main(){
FILE * test= fopen("book.txt","r");
char *wp;
while(!feof(test))
{
wp=(char*)malloc(sizeof(char));
fscanf(test,"%s",wp);
printf("%s",(char)wp);
}
return;
}
There are so many errors in your code that I'm just going to show you a proper way to do it.
// Include needed header files.
#include <stdio.h> // fopen, fprintf, fgets, printf, fclose
#include <stdlib.h> // exit, EXIT_FAILURE
#include <string.h> // strchr
int main(){
// Allocate more than enough space to hold a line.
char line[256];
FILE *file = fopen("book.txt","r");
// Ensure that file has opened.
if (file == NULL) {
fprintf(stderr, "Can't open file.\n");
exit(EXIT_FAILURE); // Return an integer indicating failure.
}
// Use fgets to avoid buffer overflow.
// Test for end-of-file directly with the input function.
while (fgets(line, sizeof(line), file)) {
// Remove newline if present
char *p = strchr(line, '\n');
if (p != NULL) *p = '\0';
printf("%s\n", line);
}
// Explicitly close file.
fclose(file);
return 0; // Return an integer (0 or EXIT_SUCCESS indicates success)
}
Related
I am trying to filter out comments from a text file denoted by '#'. I am having trouble looping through the entire file and printing the output to the terminal. The code removes the first line of text and the second lines comments as it should but does not continue past line 2 (prints 4, 2), any help would be appreciated. I'm definitely missing something as I have had to learn two semesters of C in a weekend and don't totally have a grasp on all of its usage.
The file being read
# this line is a full comment that might be pseudo-code or whatever
4, 2 # 4, 3
1
# 9
7
endNode
endNet
The program
#include <stdio.h>
#include <string.h>
#define BUFF_SIZE 1024
#define COMMENT_MARKER '#'
int main()
{
FILE *fp;
char buffer[BUFF_SIZE];
if ((fp = fopen("F:\\PythonProjects\\C\\text.txt", "r")) == NULL)
{
perror("Error opening file");
exit(1);
}
while (fgets(buffer, BUFF_SIZE, fp) != NULL)
{
char *comment = strchr(buffer, COMMENT_MARKER);
if (comment != NULL)
{
size_t len = strlen(comment);
memset(comment, '\0', len);
printf("%s", buffer);
}
}
fclose(fp);
}
Your current code only prints out a line if a # is found in it. It skips printing lines without any comment. And because you set everything from the first # to the end of the string to nul bytes, it won't print a newline after each line, meaning the results all run together.
You can fix these issues by moving the output after the comment removal block, and always printing out a newline. This means that in lines without comments, you have to do something about the newline at the end (if any; it could be missing because of a long line or the input file lacking one after the last line) so you don't get two newlines after each non-comment line.
Luckily, there are ways in standard C to find the first occurrence of one of a set of character, not just a single character. You can look for either the comment character or newline in a single pass through the line, and replace it with a single nul byte - no need to memset() everything after it to 0's. Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // Needed for exit()
#define BUFF_SIZE 1024
#define COMMENT_MARKER '#'
int main()
{
FILE *fp;
char buffer[BUFF_SIZE];
if ((fp = fopen("text.txt", "r")) == NULL)
{
perror("Error opening file");
exit(1);
}
char tokens[3] = { COMMENT_MARKER, '\n', '\0' };
while (fgets(buffer, BUFF_SIZE, fp) != NULL)
{
// Look for the first # or newline in the string
char *comment_or_nl = strpbrk(buffer, tokens);
if (comment_or_nl)
{
// and if found, replace it with a nul byte
*comment_or_nl = '\0';
}
// Then print out the possibly-truncated string (puts() adds a newline)
puts(buffer);
}
fclose(fp);
return 0;
}
Here is your code, minimally adapted to achieve the objective.
#include <stdio.h>
#include <string.h>
#define BUFF_SIZE 1024
#define COMMENT_MARKER '#'
int main()
{
FILE *fp;
if ((fp = fopen("F:\\PythonProjects\\C\\text.txt", "r")) == NULL)
{
perror("Error opening file");
exit(1);
}
char buffer[BUFF_SIZE]; // declare variables proximate to use
while (fgets(buffer, BUFF_SIZE, fp) != NULL)
{
char *comment = strchr(buffer, COMMENT_MARKER);
if (comment != NULL)
{
strcpy( comment, "\n" ); // Just clobber the comment section
}
printf("%s", buffer); // Always print something
}
fclose(fp);
}
I am new to C and I came across an issue when using fscanf to read all strings from a .txt file.
The code is as follow:
#include <stdlib.h>
#include <stdio.h>
int main() {
FILE *spIn;
char *numIn;
spIn = fopen("data.txt", "r");
if (spIn == NULL) {
printf("Can't Open This File \n");
}
while ((fscanf(spIn, "%s", numIn)) == 1) {
printf("%s\n", numIn);
};
fclose(spIn);
return 1;
}
This throws an error: Segmentation fault: 11.
The original data on txt file is:
1 2 345 rrtts46
dfddcd gh 21
789 kl
a mix of ints, strings, white space and newline characters.
At least 4 candidate undefined behaviors (UB) that could lead to a fault of some kind.
Code fails to pass to fscanf(spIn,"%s",numIn) an initialized pointer.
Code calls fscanf() even if fopen() fails.
Code calls fclose() even if fopen() fails.
No width limit in fscanf(spIn,"%s",numIn)), worse than gets().
Text files really do not have strings ('\0' terminated data) nor int, they have lines (various characters with a '\n' termination).
To read a line in and save as a string, use fgets(). Do not use fscanf() to read lines of data.
#include <stdlib.h>
#include <stdio.h>
int main() {
FILE *spIn = fopen("data.txt", "r");
if (spIn == NULL) {
printf("Can't Open This File \n");
} else {
char buf[100];
while (fgets(buf, sizeof buf, spIn)) {
printf("%s", buf);
}
fclose(spIn);
}
}
char* numIn is a pointer, and it is uninitalized, you can't really store anything in it, you need to either allocate memory for it or make it point to some valid memory location:
#include<stdlib.h> // for malloc
char* numIn = malloc(100); // space for 99 char + null terminator byte
//...
while ((fscanf(spIn, "%99s", numIn)) == 1)
{
printf("%s\n",numIn);
};
Or:
char str[100];
char *numIn = str;
Which in this small code makes little sense, you should probably make numIn a fixed size array to begin with:
char numIn[100];
Note that that you should use a width specifier in *scanf to avoid buffer overflow. This still has a problem though, it will read word by word, instead of line by line.
Looking at your input file, using fgets seems like a better option, it can read complete lines, including spaces:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *spIn;
char numIn[100];
spIn = fopen("data.txt", "r");
if (spIn != NULL)
{
while ((fgets(numIn, sizeof numIn, spIn)))
{
numIn[strcspn(numIn, "\n")] = '\0'; // removing \n
printf("%s\n", numIn);
}
fclose(spIn);
}
else
{
perror("Can't Open This File");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Since fgets also parses the \n character, I'm removing it with strcspn.
Though you do verify the return value of fopen the execution continues even if it fails to open, I also addressed that issue.
but I keep getting this error when I run this program. I think it's because of the fgets function. I tried initializing the input variable to NULL to see if that'll help, but it didn't. I also have a hunch that I might need to malloc to solve the problem. But your help is highly appreciated.
int main(int argc, char* argv[])
{
char* input = NULL;
// ensure one and only one command line argument
if (argc != 2)
{
printf("Usage: %s [name of document]\n", argv[0]);
return 1;
}
// open a new document for writing
FILE* fp = fopen(argv[1], "w");
// check for successful open
if(fp == NULL)
{
printf("Could not create %s\n", argv[1]);
return 2;
}
// get text from user and save to file
while(true)
{
// get text from user
printf("Enter a new line of text (or \"quit\"):\n");
fgets(input, 50, stdin);
// if user wants to quit
if (input != NULL && strcmp(input, "quit") == 0)
{
free(input);
break;
}
// if user wants to enter text
else if (input != NULL)
{
fputs(input, fp);
fputs("\n", fp);
printf("CHA-CHING!\n\n");
free(input);
}
}
// close the file and end successfuly
fclose(fp);
return 0;
}
You never malloc-ed input, so yeah, fgets is dereferencing the NULL pointer as its buffer, and that's going to die. Either change input to a stack array (and remove the free for it) or actually call malloc to allocate memory so input isn't pointing to NULL.
Their are some problems in your code.
You have not allocated memory to input character pointer. Hence you can't store characters in it, hence you get segmentation fault.
Also you are freeing more than once, which is incorrect.
So, a code, with the above modification would be something like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
char* input = malloc(sizeof(char) * 50);
// ensure one and only one command line argument
if (argc != 2)
{
printf("Usage: %s [name of document]\n", argv[0]);
return 1;
}
// open a new document for writing
FILE* fp = fopen(argv[1], "w");
// check for successful open
if(fp == NULL)
{
printf("Could not create %s\n", argv[1]);
return 2;
}
// get text from user and save to file
while(1)
{
// get text from user
printf("Enter a new line of text (or \"quit\"):\n");
fgets(input, 50, stdin);
// if user wants to quit
if (input != NULL && strcmp(input, "quit\n") == 0)
{
free(input);
break;
}
// if user wants to enter text
else if (input != NULL)
{
fputs(input, fp);
fputs("\n", fp);
printf("CHA-CHING!\n\n");
// free(input);
}
}
// close the file and end successfuly
fclose(fp);
return 0;
}
Hope it helps your problem.
Cheers.
While you can use malloc() here, it is not really necessary. You can #define a reasonable maximum line length, and declare a character array to hold the input. If you do this, you can remove the frees from your code.
You also have an issue with the way that you are using fgets(). The trailing \n is kept by fgets(), but your comparisons are ignoring this. Consequently, input is never equal to "quit", and is certainly never NULL. I have included some code that removes the trailing newline after reading into input; the code also clears any remaining characters from the input stream, which is possible in the event that the user enters more than MAXLINE - 1 characters. The test for text input is then simply if (input[0]). Alternatively, you could change your tests to take into account the extra '\n' character.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define MAXLINE 1000
int main(int argc, char* argv[])
{
char input[MAXLINE];
char *ch; // used to remove newline
char c; // used to clear input stream
// ensure one and only one command line argument
if (argc != 2)
{
printf("Usage: %s [name of document]\n", argv[0]);
return 1;
}
// open a new document for writing
FILE* fp = fopen(argv[1], "w");
// check for successful open
if(fp == NULL)
{
printf("Could not create %s\n", argv[1]);
return 2;
}
// get text from user and save to file
while(true)
{
// get text from user
printf("Enter a new line of text (or \"quit\"):\n");
fgets(input, MAXLINE, stdin);
// remove trailing newline
ch = input;
while (*ch != '\n' && *ch != '\0') {
++ch;
}
if (*ch) {
*ch = '\0';
} else { // remove any extra characters in input stream
while ((c = getchar()) != '\n' && c != EOF)
continue;
}
// if user wants to quit
if (strcmp(input, "quit") == 0)
{
break;
}
// if user wants to enter text
else if (input[0])
{
fputs(input, fp);
fputs("\n", fp);
printf("CHA-CHING!\n\n");
}
}
// close the file and end successfuly
fclose(fp);
return 0;
}
I think it's because of the fgets function.
Yes: passing NULL pointer to fgets makes no sense, isn't allowed, and will cause a crash.
I might need to malloc to solve the problem.
You need to pass a pointer to a suitable buffer for fgets to read input into. Whether that buffer is malloced, a local or a global array, is irrelevant.
TL;DR: think about what you are doing.
It's been years since I programmed in C, and so I've been struggling a lot just to do a simply "get filename & path from stdin, read file, print file to stdout" task, which I know shouldn't be that hard but ya. Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void) {
int c;
FILE *file;
//scanf("%s", filename);
char *filename;
filename = (char *)malloc(200 * sizeof(char));
read(STDIN_FILENO, filename, 200);
printf("%s", filename);
file = fopen(filename, "r");
if (file) {
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
} else {
printf("File not found.");
}
printf("\n");
return(0);
}
I my code continues to simply print out File not found., when I know for a fact my file path and everything is correct (not only because I literally drop it and past it into terminal from my folder with Mac OSX El Capitan - what a lovely feature, but also) because I had a different version of this program using scanf which found the file and read it perfectly fine, (as you can see I have it commented out on my code).
There is another program I'm writing that just uses this one, and I got rid of the scanf because I think it was negatively affecting other things in that program, so I want to be able to use read()
If anyone has any advice on how I can fix this or why this isn't working, that would be greatly appreciated as I've been at this for hours already and would very much like to move on to my actual program that I need to code!
THANKS A BUNCH
You must remove the '\n' new line character that is being read and stored into the filename buffer.
One of the many was to do it is include string.h and after reading the filename
char *newline = strchr(filename, '\n');
if (newline != NULL)
*newline = '\0';
Also, use fgets() instead of read() because that way the program is more portable. And more importantly, read() will not add the null terminator which is very important in order to use the buffer as a string — to pass it to fopen() for example — correctly. If you want to use read try something like this
ssize_t length;
char filename[200];
length = read(STDIN_FILENO, filename, sizeof(filename) - 1);
if (length <= 0)
return -1; // No input or input error
if (filename[length] == '\n')
filename[--length] = '\0';
else
filename[length] = '\0';
But otherwise, try this which is simpler
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *file;
char filename[200];
char *newline;
if (fgets(filename, sizeof(filename), stdin) == NULL)
return -1; // Input error / EOF
newline = strchr(filename, '\n');
if (newline) // ? is a newline present?
*newline = '\0';
printf("**%s**\n", filename); // ** will help checking for
// the presence of white spaces.
file = fopen(filename, "r");
if (file) {
int chr;
while ((chr = fgetc(file)) != EOF)
fputc(chr, stdout);
fclose(file);
} else {
printf("File not found.");
}
printf("\n");
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;
}