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.
Related
I'm new to programming in C. And I'm trying to print the first 10 lines of a text file. When I run my program with a text file containing 11 lines of text, only the first line is displayed. I'm not sure why it does that, but I suspect there is something wrong in my while loop. Can someone please help me?
#include <stdio.h>
int main(int argc, char *argv[]){
FILE *myfile;
char content;
int max = 0;
// Open file
myfile = fopen(argv[1], "r");
if (myfile == NULL){
printf("Cannot open file \n");
exit(0);
}
// Read the first 10 lines from file
content = fgetc(myfile);
while (content != EOF){
max++;
if (max > 10)
break;
printf ("%c", content);
content = fgetc(myfile);
}
fclose(myfile);
return 0;
}
You have been already advised to use fgets. However, if your file has lines of unknown length, you may still want to use fgetc. Just make sure you count only newlines, not all characters:
int max = 0;
int content;
while ((content = fgetc(myfile)) != EOF && max < 10){
if (content == '\n') max++;
putchar(content);
}
fgetc() returns the next character in the file, not the next line. You probably want to use fgets() instead, which reads up to the next newline character into a buffer. Your code should probably end up with something like:
// allocate 1K for a buffer to read
char *buff = malloc(1024);
// iterate through file until we are out of data or we read 10 lines
while(fgets(buff, 1024, myfile) != NULL && max++ < 10) {
printf("%s\n", buff);
}
free(buff);
// close your file, finish up...
Read more about fgets() here: https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm
fgetc function reads the next character not the next ine. for reading the number of lines you should use fgets function. this function reads the full string till the end of the one line and stores it in a string.
your code Shuld be as:-
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *myfile;
char content[200];
int max = 0;
// Open file
myfile = fopen(argv[1], "r");
if (myfile == NULL)
{
printf("Cannot open file \n");
exit(0);
}
// Read the first 10 lines from file
fgets(content, 200, myfile);
while (content != EOF)
{
max++;
if (max > 10)
break;
printf("%s", content);
fgets(content, 200, myfile);
}
fclose(myfile);
return 0;
}
I am creating a program that takes two command-line arguments: the first line argument is the name of the file to be copied and the second is the new file. If the second argument is missing, copy the file to stdout. If both arguments are missing, the program should read from stdin and print to stdout ie. ./a.out input.txt output.txt
I did the following but I'm facing a problem where scanf keeps looping and does not quit:
int main(int argc, char *argv[]) `
{
char text[10];
FILE *input;
FILE *output;
char ch;
printf("%s", argv[0]);
if (argc == 3)
{
input = fopen(argv[1], "r");
output = fopen(argv[2], "w");
while ((ch = fgetc(input)) != EOF)
{
fputc(ch, output);
ch = fgetc(output);
}
}
if (argc == 2)
{
input = fopen(argv[1], "r");
while ((ch = fgetc(input)) != EOF)
{
printf("%c", ch);
}
printf("\n");
}
if (argc == 1)
{
scanf("%c", text);
// here it keeps looping
}
fclose(input);
return 0;
}
Screen shot with cursor at end of line after some input before return is hit
It's not looping, it's waiting for input. You've requested scanf("%c"), a character, but scanf won't continue until you press enter. I think you meant scanf("%s") or getch(), but it isn't clear.
It will throw an error on the next line as fclose() is closing a FILE* that isn't initialized in the case of only 1 argument.
You could probably rework this homework example to use fopen() on STDIN/STDOUT in the case of missing parameters so that you aren't writing redundant code.
There are multiple problems in your code:
You output argv[0] to stdout: if argc < 3, you are supposed to copy to stdout, this extra output is corrupting the output. You might instead output to stderr or remove this line completely.
you do not check for fopen failure, causing undefined behavior if either file cannot be opened.
ch has type char which is too small to accommodate for all return values of fgetc(). On machines with 8-bit bytes, fgetc() has 257 possible return values, you must make ch an int to reliably distinguish EOF from all other return values.
in the fgetc() / fputc() loop, you read 2 bytes in each iteration of the loop but only write one byte.
the scanf() on the last case is simply waiting for input as you are supposed to copy from stdin to stdout, but the program will stop as soon as you hit the Enter key. You should just use the same fgetc()/fputc() loop for all copying loops.
you should include <stdio.h>
Here is a modified version:
int main(int argc, char *argv[]) {
FILE *input = stdin;
FILE *output = stdout;
int ch;
if (argc > 1) {
input = fopen(argv[1], "r");
if (input == NULL) {
fprintf("cannot open input file %s\n", argv[1]);
return 1;
}
}
if (argc > 2) {
output = fopen(argv[2], "w");
if (output == NULL) {
fprintf("cannot open output file %s\n", argv[2]);
return 1;
}
}
while ((ch = fgetc(input)) != EOF) {
fputc(ch, output);
}
if (argc > 2) {
fclose(output);
}
if (argc > 1) {
fclose(input);
}
return 0;
}
I am trying to repeatedly read a string from the command line and print it to a file. This is my code:
int main ()
{
FILE* fp=fopen("test.txt","w");
char* tofile[10];
while(1){
printf("cat: ");
scanf("%s",tofile);
fprintf(fp,"%s\n",tofile);
}
return 0;
}
It works just fine outside the loop. But inside, it just doesn't print.
The fprintf function returns the correct amount of characters it has to print.
Note: I know there's a similar question out there, but it hasn't been answered yet, and I hope my code can help in this matter since it's simpler.
Well first it doesn't seem that what you want is reading on the command line.
The command line what you write right when you execute your program such as:
./main things that are on the command line
What it seems you want to do is to read on the standard input.
What you should consider is to use the fgets function, as it has a limit of characters to be read, so that you can store them "safely" into a buffer, like your tofile.
As you want to read on the standard input you can use the stdin stream (which is a FILE* that is automatically created for every program)
The line goes
fgets(tofile, 10, stdin);
Your loop becoming :
while (fgets(tofile, 10, stdin) != NULL) {
printf("cat: ");
fprintf(fp, "%s\n", tofile);
}
meaning: as long as we can read on the standard input, print "cat :" and store what we just read in the file controlled by the stream pointer fp.
Some important stuff
When you try to open a stream it may fail and you should test it:
char filename[] = "test.txt";
FILE *fp = fopen(filename, "w");
if (fp == NULL) {
fprintf(stderr, "Failed to open the file of name : %s", filename);
return EXIT_FAILURE;
}
Right before exiting your main, you should also close the file and check if it has succeeded, like that for example:
if (fclose(fp) != 0) {
fprintf(stderr, "Failed to close the file of name : %s", filename);
return EXIT_FAILURE;
}
The whole thing becomes:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char filename[] = "test.txt";
FILE *fp = fopen(filename, "w");
if (fp == NULL) {
fprintf(stderr, "Failed to open the file of name : %s", filename);
return EXIT_FAILURE;
}
char tofile[10];
printf("cat: ");
while (fgets(tofile, 10, stdin) != NULL) {
printf("cat: ");
fprintf(fp, "%s\n", tofile);
}
if (fclose(fp) != 0) {
fprintf(stderr, "Failed to close the file of name : %s", filename);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Improvements
I don't know if it is just a little program or it aspires to become a greater program.
In the last case you should consider using defines and not a magical number such as
#define BUFFER_MAX_SIZE 10
char tofile[BUFFER_MAX_SIZE];
while (fgets(tofile, BUFFER_MAX_SIZE, stdin) != NULL) { ... }
This helps for readability and makes the program less apt to debug when modifying such a size. Because with the define all the part of the code needing the size will still be fully functional without modifying them.
Please also keep in mind that your tofile acts as a buffer, and it's really a small buffer that can easily be overflowed.
This will work. fgets() returns the string it reads from the specified file pointer. If this string returns only a newline ("\n"), that means nothing was entered at stdin.
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *fp = fopen("test.txt","w");
// always check if fopen() == null
if (!fp) {
fprintf(stderr, "Could not write to file\n");
return 1;
}
char tofile[30];
printf("cat: ");
while (fgets(tofile, 30, stdin)) {
if (strcmp(tofile, "\n") == 0)
break;
fprintf(fp, "%s", tofile);
printf("cat: ");
}
// always fclose()
fclose(fp);
return 0;
}
Edited code.
I have a question which maybe fairly simple. I have a file input.txt which is:
cat input.txt
testsuite1
test1
summary information of test
FAIL
testsuite2
test1
summary info ya
PASS
I am writing a program just to read each of these strings into variables and do further processing. What is the best way to do it? I am currently doing:
main() {
FILE *fp;
char testsuite[100],testname[100],summary[100],result[100];
fp = fopen("input.txt", "r");
while(1) {
if(fgets(testsuite,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(testname,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(summary,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(result,99,fp) == NULL)
{
ferror(fp);
break;
}
printf("testsuite: %s testname:%s summary:%s result:%s \n",testsuite,testname,summary,result);
}
fclose(fp);
}
Is there a better way to do it? The problem I am currently facing is that, if input.txt contains even one blank line, the blank like is read into a variable. Whats the best way to avoid it?
Thanks!
You should write your own function that skips empty lines (e.g. called getline()) and use it instead of fgets():
char *getline(char *buf, int size, FILE *fp)
{
char *result;
do {
result = fgets(buf, size, fp);
} while( result != NULL && buf[0] == '\n' );
return result;
}
You could now refine that function to also skip lines that consist of blanks only or whatever you need.
You can remove all blank lines of your files before your loop while.
After the open you parse the whole file and remove the blank ;).
But it don't seems like the best way to do it.
Overwise you can check after each fget if your variables are empty, and in this case, fget again.
Hope that will be helpfull.
If you do this, you will not be able to use the strings you read once loop quits, since each loop overwrites each string in the buffer. However, you could store your strings in a struct array:
typedef struct {
testsuite[100];
testname[100];
summary[100];
result[100];
}test;
test test_array[2];
int main(){
int iIndex=0;
FILE* fpPtr=NULL;
fpPtr = fopen("input.txt", "r");
if(fpPtr==NULL){ //<--- it is very important to check if fopen fails
perror("fopen");
}
for(iIndex=0; iIndex<2; iIndex++){ // 2 because it is the number of elements in test_array
if(fgets(test_array[i].testsuite,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(test_array[i].testname,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(test_array[i].summary,99,fp) == NULL)
{
ferror(fp);
break;
}
if(fgets(test_array[i].result,99,fp) == NULL)
{
ferror(fp);
break;
}
}
}
You can detect blank lines by checking for a newline character at position 0:
fgets(cBuffer, sizeof(cBuffer), fpPtr);
//<-- if the file was created on windows, check for '\r' instead, since a new line in windows is \r\n
if(cBuffer[0]=='\n')
{
printf("blank line"\n);
}
I have been working on a small exercise for my CIS class and am very confused by the methods C uses to read from a file. All that I really need to do is read through a file line by line and use the information gathered from each line to do a few manipulations. I tried using the getline method and others with no luck.
My code is currently as follows:
int main(char *argc, char* argv[]){
const char *filename = argv[0];
FILE *file = fopen(filename, "r");
char *line = NULL;
while(!feof(file)){
sscanf(line, filename, "%s");
printf("%s\n", line);
}
return 1;
}
Right now I am getting a seg fault with the sscanf method and I am not sure why. I am a total C noob and just wondering if there was some big picture thing that I was missing.
Thanks
So many problems in so few lines. I probably forget some:
argv[0] is the program name, not the first argument;
if you want to read in a variable, you have to allocate its memory
one never loops on feof, one loops on an IO function until it fails, feof then serves to determinate the reason of failure,
sscanf is there to parse a line, if you want to parse a file, use fscanf,
"%s" will stop at the first space as a format for the ?scanf family
to read a line, the standard function is fgets,
returning 1 from main means failure
So
#include <stdio.h>
int main(int argc, char* argv[])
{
char const* const fileName = argv[1]; /* should check that argc > 1 */
FILE* file = fopen(fileName, "r"); /* should check the result */
char line[256];
while (fgets(line, sizeof(line), file)) {
/* note that fgets don't strip the terminating \n, checking its
presence would allow to handle lines longer that sizeof(line) */
printf("%s", line);
}
/* may check feof here to make a difference between eof and io failure -- network
timeout for instance */
fclose(file);
return 0;
}
To read a line from a file, you should use the fgets function: It reads a string from the specified file up to either a newline character or EOF.
The use of sscanf in your code would not work at all, as you use filename as your format string for reading from line into a constant string literal %s.
The reason for SEGV is that you write into the non-allocated memory pointed to by line.
In addition to the other answers, on a recent C library (Posix 2008 compliant), you could use getline. See this answer (to a related question).
Say you're dealing with some other delimiter, such as a \t tab, instead of a \n newline.
A more general approach to delimiters is the use of getc(), which grabs one character at a time.
Note that getc() returns an int, so that we can test for equality with EOF.
Secondly, we define an array line[BUFFER_MAX_LENGTH] of type char, in order to store up to BUFFER_MAX_LENGTH-1 characters on the stack (we have to save that last character for a \0 terminator character).
Use of an array avoids the need to use malloc and free to create a character pointer of the right length on the heap.
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
}
/* get a character from the file pointer */
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = '\0';
fprintf(stdout, "%s\n", line);
break;
}
else if (tempChar == '\n') {
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
fprintf(stdout, "%s\n", line);
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}
If you must use a char *, then you can still use this code, but you strdup() the line[] array, once it is filled up with a line's worth of input. You must free this duplicated string once you're done with it, or you'll get a memory leak:
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
char *dynamicLine = NULL;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
}
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = '\0';
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
break;
}
else if (tempChar == '\n') {
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}