I'm trying to relearn C from dabbling with it about 5 year ago. Specifically, I'm trying to learn how to extract a number of operations from main and make them into a function, with the aim of moving them to a library file next.
This seems to be working:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
struct arguments {
char *word_file; /* Default name for input file */
} arguments;
int main (int argc, char *argv[]) {
arguments.word_file = "dummy";
FILE *fp;
fp = fopen(arguments.word_file, "r");
if (fp == NULL) { /* If fopen failed... */
fprintf(stderr, "Error: Unable to open file %s: %s\n",
arguments.word_file, strerror (errno));
exit (8);
}
char word[60];
fgets (word, sizeof(word), fp);
printf("Word is %s\n", word);
}
By the way, 'dummy' is:
$ cat dummy
dog
cat
$
No matter how I try this, it either gives me compile errors, or seg faults when I run it:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
struct arguments {
char *word_file; /* Default name for input file */
} arguments;
void getfile(FILE *fp) {
fp = fopen(arguments.word_file, "r");
if (fp == NULL) { /* If fopen failed... */
fprintf(stderr, "Error: Unable to open file %s: %s\n",
arguments.word_file, strerror (errno));
exit (8);
}
}
int main (int argc, char *argv[]) {
arguments.word_file = "dummy";
FILE *fp;
getfile(fp);
char word[60];
fgets (word, sizeof(word), fp);
printf("Word is %s\n", word);
}
I've tried changing from *fp to fp to &fp without success. I'm sure that there's something that I don't understand about file pointers, but can't figure it out.
Thanks for any help and suggestions.
-Kevin
You have two choices
First, have 'getfile' return the file handle (this is the most idiomatic way in c)
FILE *getfile() {
FILE *fp = fopen(arguments.word_file, "r");
if (fp == NULL) { /* If fopen failed... */
fprintf(stderr, "Error: Unable to open file %s: %s\n",
arguments.word_file, strerror (errno));
exit (8);
}
return fp;
}
and in main
FILE *fp = getfile(fp);
or have getfile update the fp value based , using c-style 'pass by reference'
void getfile(FILE **fp) {
*fp = fopen(arguments.word_file, "r");
if (*fp == NULL) { /* If fopen failed... */
fprintf(stderr, "Error: Unable to open file %s: %s\n",
arguments.word_file, strerror (errno));
exit (8);
}
}
in main
File *fp = NULL;
getfile(&fp);
fp shouldn't be an argument to getfile(), it should be the return value.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
struct arguments {
char *word_file; /* Default name for input file */
} arguments;
FILE *getfile() {
FILE *fp = fopen(arguments.word_file, "r");
if (fp == NULL) { /* If fopen failed... */
fprintf(stderr, "Error: Unable to open file %s: %s\n",
arguments.word_file, strerror (errno));
exit (8);
}
return fp;
}
int main (int argc, char *argv[]) {
arguments.word_file = "dummy";
FILE *file_ptr;
file_ptr = getfile();
char word[60];
fgets (word, sizeof(word), file_ptr);
printf("Word is %s\n", word);
}
If there's some reason you really need to pass it as a parameter, see Changing address contained by pointer using function
The problem is that the pointer fp is passed to the function getfile by value.
getfile(fp);
That is the function deals with a copy of the value of the passed pointer fp. So changing the copy in the function does not reflect on the value of the original pointer.
You need to pass the pointer by reference.
In C passing by reference means passing an object indirectly through a pointer to it. Dereferencing the pointer you can get a direct access to the original object.
So declare and define the function like
void getfile(FILE **fp) {
*fp = fopen(arguments.word_file, "r");
if ( *fp == NULL) { /* If fopen failed... */
fprintf(stderr, "Error: Unable to open file %s: %s\n",
arguments.word_file, strerror (errno));
exit (8);
}
}
and call the function like
getfile(&fp);
Related
I am trying to read from a file, and here is my code, but as I run my code nothing shows up. Have I used the getline() function incorrectly? I can not understand my problem.
const char *READ = "r";
/**
* main - Entry point of my program
*
* Return: On success, it returns 0. On
* error it returns -1
*/
int main(int ac, char **av)
{
FILE *fpointer;
char *lineptr = NULL;
size_t *n = 0;
int line_number = 1;
if (ac != 2)
{
fprintf(stderr, "USAGE: monty file\n");
exit(EXIT_FAILURE);
}
fpointer = fopen(av[1], READ);
if (fpointer == NULL)
{
fprintf(stderr, "Error: Can't open file %s\n", av[1]);
exit(EXIT_FAILURE);
}
while (getline(&lineptr, n, fpointer) != -1)
{
printf("Line %d: %s\n", line_number, lineptr);
line_number++;
}
return (0);
}
getline(&lineptr, n, fpointer) returns -1. You did not explicitly check this and print an error message.
Checking errno it's because of EINVAL: invalid argument. Also good to check errno.
Reason is that n is NULL, while a pointer to an existing size_t is required.
BTW, indenting with 8 spaces is rather uncommon; I'd stay with 4 space. (Also, never use TAB characters.)
It's advisable to stick with extremely common argc and argv.
Nice you put {s on a further empty line; I like that style.
You'd get this:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
const char *READ = "r";
int main(int argc, char **argv)
{
FILE *fpointer;
char *lineptr = NULL;
size_t n;
int line_number = 1;
if (argc != 2)
{
fprintf(stderr, "USAGE: monty file\n");
exit(EXIT_FAILURE);
}
fpointer = fopen(argv[1], READ);
if (fpointer == NULL)
{
fprintf(stderr, "Error: Can't open file '%s'.\n", argv[1]);
exit(EXIT_FAILURE);
}
if (getline(&lineptr, &n, fpointer) == -1)
{
printf("Failed to read file '%s': %s.\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
do
{
printf("Line %4d: %s\n", line_number, lineptr);
line_number++;
}
while (getline(&lineptr, &n, fpointer) != -1);
return (0);
}
Declaration of getline:
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
As an output parameter, the type of n is size_t *. It points to a space for writing by getline.
But in your code, n points to 0, which is NOT a vaild addr to write in.
I understand that popen doesn't allow simultaneous read and write.
To get around this, I created two files, 1.c for writing, and 2.c for reading. The files are included below.
When I run 1.out, I get the expected output on stdout:
bodhi#bodhipc:~/Downloads$ ./1.out
Stockfish 11 64 BMI2 by T. Romstad, M. Costalba, J. Kiiski, G. Linscott
bodhi#bodhipc:~/Downloads$
However, 2.out doesn't give any output on stdout:
bodhi#bodhipc:~/Downloads$ ./2.out
bodhi#bodhipc:~/Downloads$
Where am I going wrong?
1.c:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
FILE *fp;
char path[1035];
/* Open the command for writing. */
fp = popen("./stockfish", "w");
if (fp == NULL) {
printf("Failed to run command\n" );
exit(1);
}
fprintf(fp,"uci\n");
/* close */
pclose(fp);
return 0;
}
2.c:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
FILE *fp;
char path[1035];
/* Open the command for reading. */
fp = popen("./1.out", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit(1);
}
/* Read the output a line at a time - output it.*/
while (fgets(path, sizeof(path), stdout) != NULL) {
printf("%s", path);
printf("Done!\n");
}
/* close */
pclose(fp);
return 0;
}
while (fgets(path, sizeof(path), stdout) != NULL) {
you don't want to read from stdout, instead:
while (fgets(path, sizeof(path), fp) != NULL) {
I am unable to save a char array using fprint() and i cannot figure out why. The below codes compliles correctly but saves nothing to file. Please advise.
static char bitSpecial[100];
int main(int argc, char *argv[]) {
FILE *fp
fp = fopen(thefilename, "w+");
if (fp == NULL) {
printf("I couldn't open file for writing.\n");
exit(0);
}
/* populate bitSpecial one character at the time and verify array is full */
fprintf(fp,"%s", bitSpecial);
if (fclose(fp) != 0) puts("Unable to close the file");
return
}
It'll be easier to identify the problem with the full code. I tried the following snippet and it worked:
#include <stdio.h>
#include <string.h> // for strerror
#include <errno.h> // for errno
static char bitSpecial[100];
int main(int argc, char *argv[])
{
char * thefilename = "test";
FILE *fp;
fp = fopen(thefilename, "w+");
if (fp == NULL) {
printf("I couldn't open file for writing.\n");
return 1;
}
/* populate bitSpecial one character at the time and verify array is full */
bitSpecial[0] = 'a';
bitSpecial[1] = '\n';
bitSpecial[2] = '\0'; // terminator
if (fprintf(fp,"%s", bitSpecial) < 0)
printf("[+] fprintf failed with '%s'\n", strerror(errno));
if (fclose(fp) != 0)
puts("Unable to close the file");
return 0;
}
Verify that you put a null terminator (\0) at the end of bitSpecial, and check the return value of fprintf.
I am curious what is the best way to open multiple files. I know you use a combination of FILE *inputfp1; and inputfp1 = fopen(argv[1], "r"); then check for errors. I would like to know the best way to do this.
Is it best to open and close one file at a time like this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char **argv) {
char line[80] = {0};
FILE *inputfp1;
//input = fopen("myfile.txt", "r");
inputfp1 = fopen(argv[1], "r"); //Open file for read.
if (inputfp1 == NULL)
{
printf("Error opening file %s!",argv[1]); //Program prints error message and closes if file is not found
exit(0);
}
if( argc == 7 )
{
/*printf("The first argument supplied is %s\n", argv[1]);
printf("The second argument supplied is %s\n", argv[2]);
printf("The third argument supplied is %s\n", argv[3]);
printf("The first argument supplied is %s\n", argv[4]);
printf("The second argument supplied is %s\n", argv[5]);
printf("The third argument supplied is %s\n", argv[6]);
printf("The third argument supplied is %s\n", argv[7]);*/
}
else if( argc > 7 )
{
printf("Too many arguments supplied.\n");
exit( 1 );
}
else
{
printf("Not enough arguments supplied. \n");
exit( 1 );
}
//Unique behavior on file1
while(fgets(line, 80, inputfp1) != NULL)
{
//do work on file1
}
fclose(inputfp1);
inputfp1 = fopen(argv[2], "r"); //Open file for read.
if (inputfp1 == NULL)
{
printf("Error opening file %s!",argv[1]); //Program prints error message and closes if file is not found
exit(0);
}
//Unique behavior on file2
while(fgets(line, 80, inputfp1) != NULL)
{
//do work on file2
}
fclose(inputfp1);
return 0;
}
Is it better to create all the file pointers and open all the files at once like this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char **argv) {
char line[80] = {0};
FILE *inputfp1;
FILE *inputfp2;
FILE *inputfp3;
FILE *inputfp4;
FILE *inputfp5;
FILE *inputfp6;
//input = fopen("myfile.txt", "r");
inputfp1 = fopen(argv[1], "r"); //Open file for read.
inputfp2 = fopen(argv[2], "r"); //Open file for read.
inputfp3 = fopen(argv[3], "r"); //Open file for read.
inputfp4 = fopen(argv[4], "r"); //Open file for read.
inputfp5 = fopen(argv[5], "r"); //Open file for read.
inputfp6 = fopen(argv[6], "r"); //Open file for read.
if (inputfp1 == NULL)
{
printf("Error opening file %s!",argv[1]); //Program prints error message and closes if file is not found
exit(0);
}
//The rest of error checking.
if( argc == 7 )
{
/*printf("The first argument supplied is %s\n", argv[1]);
printf("The second argument supplied is %s\n", argv[2]);
printf("The third argument supplied is %s\n", argv[3]);
printf("The first argument supplied is %s\n", argv[4]);
printf("The second argument supplied is %s\n", argv[5]);
printf("The third argument supplied is %s\n", argv[6]);
printf("The third argument supplied is %s\n", argv[7]);*/
}
else if( argc > 7 )
{
printf("Too many arguments supplied.\n");
exit( 1 );
}
else
{
printf("Not enough arguments supplied. \n");
exit( 1 );
}
//Unique behavior on file1
while(fgets(line, 80, inputfp1) != NULL)
{
//do work on file1
}
fclose(inputfp1);
//Unique behavior on file2
while(fgets(line, 80, inputfp2) != NULL)
{
//do work on file2
}
fclose(inputfp2);
//The rest of reading and closing files.
return 0;
}
Are there any better ways I missed?
A good way of doing this would be putting all your file pointers in an array:
FILE *inputfp[6];
for(int i=0;i<6;i++)
{
inputfp[i] = fopen(argv[i+1], "r"); //Open file for read.
if (inputfp[i] == NULL)
{
printf("Error opening file %s!",argv[i+1]); //Program prints error message and closes if file is not found
exit(0);
}
}
I'd do it the first way, but use a loop:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char **argv) {
char line[80] = {0};
FILE *inputfp1;
if( argc == 7 )
{
/*printf("The first argument supplied is %s\n", argv[1]);
printf("The second argument supplied is %s\n", argv[2]);
printf("The third argument supplied is %s\n", argv[3]);
printf("The first argument supplied is %s\n", argv[4]);
printf("The second argument supplied is %s\n", argv[5]);
printf("The third argument supplied is %s\n", argv[6]);
printf("The third argument supplied is %s\n", argv[7]);*/
}
else if( argc > 7 )
{
printf("Too many arguments supplied.\n");
exit( 1 );
}
else
{
printf("Not enough arguments supplied. \n");
exit( 1 );
}
for (int i = 1; i < argc; ++i)
{
inputfp1 = fopen(argv[i], "r"); //Open file for read.
if (inputfp1 == NULL)
{
printf("Error opening file %s!",argv[i]); //Program prints error message and closes if file is not found
exit(0);
}
while(fgets(line, 80, inputfp1) != NULL)
{
//do work
}
fclose(inputfp1);
}
return 0;
}
I have the following code which reads an file name from the command line and opens this file:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv){
FILE *datei;
char filename[255];
//filename = argv[1];
//datei=fopen(filename, "r");
datei=fopen(argv[1], "r");
if(datei != NULL)
printf("File opened");
else{
printf("Fehler beim öffnen von %s\n", filename);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
This example works, but I want to write the string from the command line to the char array and pass that char array to to fopen(), but i get the compiler error
Error: assignment to expression with array type filename = argv[1];
What does this error mean and what can I do to fix it?
You must copy the string into the char array, this cannot be done with a simple assignment.
The simplistic answer is strcpy(filename, argv[1]);.
There is a big problem with this method: the command line parameter might be longer than the filename array, leading to a buffer overflow.
The correct answer therefore:
if (argc < 2) {
printf("missing filename\n");
exit(1);
}
if (strlen(argv[1]) >= sizeof(filename)) {
printf("filename too long: %s\n", argv[1]);
exit(1);
}
strcpy(filename, argv[1]);
...
You might want to output the error messages to stderr.
As a side note, you probably want to choose English or German, but not use both at the same time ;-)
An even simpler solution is to just keep a copy of the pointer argv[1] in a char *filename. Unless you modify it yourself, a very bad idea, its contents will not change for the duration of the program execution.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
FILE *datei;
char *filename;
if (argc < 2) {
fprintf(stderr, "Fehlendes Dateiname-Befehlszeilenargument\n");
return EXIT_FAILURE;
}
filename = argv[1];
datei = fopen(filename, "r");
if (datei != NULL) {
printf("Datei erfolgreich geöffnet\n");
} else {
fprintf(stderr, "Fehler beim öffnen von %s: %s\n",
filename, strerror(errno));
return EXIT_FAILURE;
}
// ...
fclose(datei);
return EXIT_SUCCESS;
}