Why do I mysteriously segfault when writing to file? - c

I wish I could i could give more information, but I genuinely have no idea what is going on here. This code opens files for appension or overwriting, depending on user arguments (appension by default). It gets as far as the fgets for user input, and then as soon as the input is entered, it segfaults and dumps core. This is strange, because before I implemented arguments (i.e. it was just ./a.out file) it worked fine, so I guess it has something to do with the new stuff about arguments...
#include <stdio.h>
#include <string.h>
int printhelp(void);
int main(int argc, char *argv[])
{
char input[256];
int loopstat = 0;
FILE *inputfile;
if (argc < 2) /* Check argc for minimum 2 arguments (i.e. cw FILE) */
{
printf("ca: missing file operand\n");
return 0;
}
else if (argc > 2) /* Check argc for more than 2 arguments (i.e. cw -o FILE) */
{
if (strncmp(argv[1], "-", 1) == 0) /* if first argument begins with "-", it must be an option, so descend into option checking */
{
if (strcmp(argv[1], "-a") == 0) /* If -a option is given, open for appending */
{
FILE *inputfile = fopen(argv[2], "a");
}
else if (strcmp(argv[1], "-o") == 0) /* If -o option is given, open for overwriting */
{
FILE *inputfile = fopen(argv[2], "w");
}
else if (strcmp(argv[1], "--help") == 0) /* If --help option is given, print help and quit */
{
printhelp();
return 0;
}
else
{
printf("cw: invalid option\n"); /* If invalid option is given, print the fact and quit*/
return 0;
}
}
}
else /* if argc is equal to 2 (i.e. "cw FILE" or "cw -o")...*/
{
if (strncmp(argv[1], "-", 1) == 0) /* Check if user has specified an option but no file (i.e. "cw -o") */
{
printf("cw: missing file operand\n"); /* If they have, print that no file is spec'd and quit */
return 0;
}
else /* If not, it's a legit file with no other arguments (e.g. "cw FILE") so open it in append mode by default */
{
FILE *inputfile = fopen(argv[2], "a");
}
}
/* Writing loop */
printf("Enter input...\n");
while (loopstat == 0) /* Get user input and write to file until they give exit command */
{
fgets(input, 256, stdin); /* Get user input */
if (strcmp(input, ":x\n") == 0) /* If input == exit command, quit */
{
printf("co: exit received, terminating...\n");
loopstat++;
}
else /* Write to file */
{
fprintf(inputfile, "%s", input);
}
}
fclose(inputfile);
}
int printhelp(void) /* Print help on --help command */
{
printf(
"Usage: ca FILE\nContinuously append input to the FILE\nca does not currently support multiple file appension.\nReport bugs to scamp#lavabit.com\n");
return 0;
}
P.S. sorry if I messed up the indentation, it's really confusing to have to add four spaces before everything in this much code.

Here you are shadowing your variable:
else /* If not, it's a legit file with no other arguments (e.g. "cw FILE") so open it in append mode by default */
{
FILE *inputfile = fopen(argv[2], "a");
}
should be
else /* If not, it's a legit file with no other arguments (e.g. "cw FILE") so open it in append mode by default */
{
inputfile = fopen(argv[2], "a");
}
You have several instances like this, so remove the declaration there as well.

You are declaring the identifier inputfile several times, but it won't be the same object at each time.
See the behavior of this program for instance (from Wikipedia):
#include <stdio.h>
int main(void)
{
char x = 'm';
printf("%c\n", x);
{
printf("%c\n", x);
char x = 'b';
printf("%c\n", x);
}
printf("%c\n", x);
}
You have to declare inputfile just once, and then assign it in if statements.
FILE *inputfile;
if (/* ... */)
inputfile = /* ... */
else if (/* ... */)
inputfile = /* ... */
else
inputfile = /* ... */

int main(int argc, char *argv[])
{
char input[256];
int loopstat = 0;
FILE *inputfile;
then you have:
if (strcmp(argv[1], "-a") == 0)
{
FILE *inputfile = fopen(argv[2], "a");
}
You should not redeclare a new object inputfile but reuse your inputfile declared at the top of your function.
Example:
inputfile = fopen(argv[2], "a");

The problem is there:
FILE *inputfile;
....
if (strcmp(argv[1], "-a") == 0)
{
FILE *inputfile = fopen(argv[2], "a");
}
By writing this way you are hiding the variable inputfile from the compiler. Thus the variable defined in the beginning stays uninitialized.
You should write it following way:
if (strcmp(argv[1], "-a") == 0)
{
inputfile = fopen(argv[2], "a");
}
So now you will use the variable defined in the top of the function.
You should read about the variable scope.

Related

How to get Command Line Arguments running in C for input and output files

I am trying to run an application in the CMD developer prompt, it should have an input file and output file using command line arguments (which i don't understand, or can't wrap my head around). But when I do it, it's running and ending but nothing is being printed to the output file.
Below is my code with non-relevant code redacted. I don't know if I'm doing something wrong in the code or the cmd line developer prompt.
The app is called printlines.exe and my command looks like this:
printlines.exe -i file.java -o output.txt
Any advice would be greatly appreciated.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define LINE 1000
void countLines(int *emptyLines, int *totalLines, int *totalComments, char *fileName, FILE *readFile)
{
char line[LINE]; // set array to store input file data
//set variables
readFile = fopen(fileName, "r");
int lines = 0;
int comments = 0;
int empty = 0;
while (fgets(line, LINE, readFile) != NULL) //while loop that reads in input file line by line
{
/*counts lines in input file works when not using
command line arguments redacted to shorten */
}
fclose(readFile);
*emptyLines = empty;
*totalLines = lines;
*totalComments = comments;
}
int main(int argc, char *argv[])
{
FILE *inputFile;
FILE *outputFile;
char *outputName;
char *inputName;
inputName = argv[1];
outputName = argv[2];
inputFile = fopen(inputName, "r");
outputFile = fopen(outputName, "w");
int emptyLines, totalLines, totalComments;
countLines(&emptyLines, &totalLines, &totalComments, inputName, inputFile);
int character;
bool aComment = false;
while ((character = fgetc(inputFile)) != EOF)
{
/* code that writes info from input to output, works
when not using command line arguments redacted to shorten*/
}
//close files
fclose(inputFile);
fclose(outputFile);
printf("There are %d total lines, %d lines of code and %d comments in the file\n", totalLines, emptyLines, totalComments);
return 0;
}
No error checking is being performed, neither for command line arguments nor for errors opening the files. I'm willing to bet you would quickly pinpoint the problem if you did the following:
//....
if(argc < 5){ // check arguments
fprintf(stderr, "Too few arguments");
return EXIT_FAILURE;
}
inputFile = fopen(inputName, "r");
if(inputFile == NULL){ // chek if file was open
fprintf(stderr, "Failed to open input file\n");
return EXIT_FAILURE;
}
outputFile = fopen(outputName, "w");
if(outputFile == NULL){ // again
fprintf(stderr, "Failed to open output file\n");
return EXIT_FAILURE;
}
//...
Note that your comand line string has 5 arguments, and the file names are at indexes 2 and 4 so you would need:
inputName = argv[2];
outputName = argv[4];
Or just remove the -i and -o since they don't seem to be doing anything.
I should also note that you can use command line arguments directly on fopen or in your function, there is no need for the two extra pointers:
inputFile = fopen(argv[2], "r");
outputFile = fopen(argv[4], "w");
//...
countLines(&emptyLines, &totalLines, &totalComments, argv[2], inputFile);

Writing file name dinamically through the code - C

I'm making a program that basically receives 2 files (a .pal and a .dic file) and outputs a file called solution file (blabla.sol). However that solution file's name depends on one of those files that the program received. How can I modify my program in order to change the output file's name depending on the name of the received file's name? In this case I want it to be the same names as my name_pal file.
Here's the program that I've already written (right now, as it is, it only outputs a file with a fixed name):
int main(int argc, char *argv[])
{
char name_dic[MAX_FILENAME_SIZE];
char name_pal[MAX_FILENAME_SIZE];
char name_sol[] = "prob0.sol";
char words_dic[MAX_WORD_SIZE];
char words_pal[MAX_WORD_SIZE];
char word_same_size[MAX_WORD_SIZE];
char dic_total[MAX_DIC_SIZE][MAX_WORD_SIZE];
char pal_total[MAX_PAL_SIZE][MAX_WORD_SIZE];
FILE *dic, *pal, *sol;
if (argc < 3)
{
printf("Missing files.\n");
exit(1);
}
strcpy(name_dic, argv[1]);
strcpy(name_pal, argv[2]);
dic = fopen(name_dic, "r");
if (dic == NULL)
{
printf("Can not open dictionary file: %s\n", name_dic);
exit(1);
}
pal = fopen(name_pal, "r");
if (pal == NULL)
{
printf("Can not open problem file: %s\n", name_pal);
exit(1);
}
sol = fopen(name_sol, "w");
if (sol == NULL)
{
printf("Can not open solution file: %s\n", name_sol);
exit(1);
}
/* rest of the code */
You can write a truncate function at the '.' and then append sol as shown in snippet below.
char name_sol[MAX_FILENAME_SIZE];
int i;
for(i=0;i<MAX_FILENAME_SIZE;i++){
name_sol[i]=name_pal[i];
if(name_sol[i]=='.') break;
}
strcpy(name_sol+i+1,"sol");
printf("%s\n",name_sol);

Open files with argv gives me file NULL

I have a program that should take the file's name from command line using argc and argv. Printing argv[1] and argv[2] show me the exactly names I passed, but passing argv[1] and argv[2] as parameters to open the files in another function just show the error line I put if can't open the file.
My main:
int main(int argc, char* argv[])
{
if (argc != 4)
{
puts("Incorrect number of parameters.");
return 1;
}
else
{
Image *a, *b;
a = OpenFile(argv[1]);
b = OenFile(argv[2]);
} /* else */
return 0;
} /* main */
The function OpenFile will return a struct filled with information from the file. Here's the first part of the function:
Image *OpenFile(char* name)
{
FILE* f = fopen(name, "r");
Image* imagem;
int temp, i, cont, data[MAX];
char aux[2];
if(f == NULL)
{
puts("Error opening file.");
return NULL;
} /* if */
...
}
I'm passing the correct names but I receive the "Error opening file." line for each file I try to open.
Edit: It's giving me "No such file or directory", but I copied the files to the directory where the .exe is placed. It's not the first time I use the file's name from command line, but it's the first time I pass as parameters to another function.
From fopen man page:
RETURN VALUE
Upon successful completion fopen(), fdopen() and freopen() return a FILE pointer. Otherwise, NULL is returned and
errno is set to indicate the error.
So You could change:
if(f == NULL)
{
puts("Error opening file.");
return NULL;
} /* if */
With:
if(f == NULL)
{
perror("fopen");
return NULL;
} /* if */
And you ll get a pretty descriptive message on the reason fopen failed.
You should include errno.h in order to use perror

Segmentation faults in C with fopen?? (not exactly sure what's causing the error)

So here's my code for my main()
int main(int argc, char **argv) {
if (argc != 3) {
puts("Invalid number of args in the input. Sorry.");
return 0;
}
if (doesItExist(argv[2]) == 0) {
return 0;
}
FILE *fpoint;
char yesorno[2];
tail = (WordN) malloc(sizeof(struct WordNode));
tail->word = "";
tail->first = (FileN) malloc(sizeof(struct FileNode));
(tail->first)->freq = -1;
ftw(argv[2], tokeForMe, 1);
/**
fpoint = fopen(argv[1], "r");
if(fpoint != NULL) { // file exists give user option to overwrite or rename
getInput("Do you want to overwrite the file? Enter only either Y or N nothing else\n", yesorno, 2);
if(yesorno[0] == 'N' || yesorno[0] == 'n') {
puts("All right. Not going to proceed with the program");
return 0;
}
else if(yesorno[0] != 'Y' && yesorno[0] != 'y') {
puts("You inputted some other character, try again \n");
getInput("Do you want to overwrite the file? Enter Y or N. Do not enter anything other than 1 Y or 1 N \n", yesorno, 2);
}
}
fclose(fpoint);
**/
FILE *index;
index = fopen(argv[1], "w");
//puts("here");
writeToIndex(index, tail->next); //tail is pointing to the first word node
puts("there");
if (doesItExist(argv[1]) == 0) {
return 0;
}
fclose(index);
TailTerminate();
return 0;
}
The code seg faults when I uncomment the part when I make a file pointer to read argv[1] to find out whether the user wants to overwrite the file specified in argv[1].
The program itself is just a program that makes a sort of indexer out of a directory of files and then prints it out. The directory path is specified in argv[2] and the path to print out the index is specified in argv[1].
Can someone help me with this? The rest of the program (the Tail nodes and such) are only to make a sort of list the words and frequencies that appear in the program.
You don't show all the functions called from main (getInput?), and they may content errors. From your commented code, I can only say that you wrote something like this:
FILE *f = fopen(...);
if (f != NULL)
{
/* use f */
}
fclose(f);
But it should be like this:
FILE *f = fopen(...);
if (f != NULL)
{
/* use f */
fclose(f);
}
That is, do not call fclose() with a NULL pointer.

How would I get more then one text file accepted?

Right now, I have something like this...
CMD console window:
c:\users\username\Desktop> wrapfile.txt hello.txt
Hello
How would I get something like this?
CMD console window:
c:\users\username\Desktop> wrapfile.txt hello.txt hi.txt
Hello Hi
with this code?
#include <stdio.h>
#include <stdlib.h>
int main(int argc[1], char *argv[1])
{
FILE *fp; // declaring variable
fp = fopen(argv[1], "rb");
if (fp != NULL) // checks the return value from fopen
{
int i;
do
{
i = fgetc(fp); // scans the file
printf("%c",i);
printf(" ");
}
while(i!=-1);
fclose(fp);
}
else
{
printf("Error.\n");
}
}
Well, first of all: in your main declaration, you should use int main(int argc, char* argv[]) instead of what you have right now. Specifying an array size makes no sense when declaring an extern variable (that's what argv and argc are). On the top of that, you are not using the correct types. argc is integer and argv is array of strings (which are arrays of chars). So argv is an array of arrays of chars.
Then, simply use the argc counter to loop through the argv array. argv[0] is the name of the program, and argv[1] to argv[n] will be the arguments you pass to your program while executing it.
Here is a good explanation on how this works: http://www.physics.drexel.edu/courses/Comp_Phys/General/C_basics/#command-line
My 2 cents.
EDIT: Here is a commented version of the working program.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
FILE *fp;
char c;
if(argc < 3) // Check that you can safely access to argv[0], argv[1] and argv[2].
{ // If not, (i.e. if argc is 1 or 2), print usage on stderr.
fprintf(stderr, "Usage: %s <file> <file>\n", argv[0]);
return 1; // Then exit.
}
fp = fopen(argv[1], "rb"); // Open the first file.
if (fp == NULL) // Check for errors.
{
printf("Error: cannot open file %s\n", argv[1]);
return 1;
}
do // Read it.
{
c = fgetc(fp); // scans the file
if(c != -1)
printf("%c", c);
} while(c != -1);
fclose(fp); // Close it.
fp = fopen(argv[2], "rb"); // Open the second file.
if (fp == NULL) // Check for errors.
{
printf("Error: cannot open file %s\n", argv[2]);
return 1;
}
do // Read it.
{
c = fgetc(fp); // scans the file
if(c != -1)
printf("%c", c);
} while(c!=-1);
fclose(fp); // Close it.
return 0; // You use int main and not void main, so you MUST return a value.
}
I hope it helps.
argv[2] would be the second file name.
Do not forget to check the value of argc to see if enough arguments are valid.
Better: use boost::program_options.
Caution: this code is not unicode-aware on Windows system, which makes it not portable. Refer to utf8everywhere.org about how to make it support all file names on this platform.

Resources