Why will this simple function cause seg fault?
int main(int argc, char** argv) {
FILE* file1;
file1 = fopen(argv[argc + 1], "wt");
fclose(file1);
}
Your fopen() is failing to open the file, so fp is NULL, so fclose() is legitimately objecting by crashing. Check the return from fopen().
Also, by definition, argv[argc] == 0 and argv[argc+1] is beyond the end of the array. In practice, on Unix systems, it will often be the name=value of the first environment variable, but it is unlikely to be a valid filename and most certainly wasn't obtained legitimately.
If your program is invoked as:
./a.out file.txt
then the file name is argv[1]; the string pointed at by argv[0] is the name of the program, a.out give or take path information, and argc == 2 and argv[2] == 0. Don't forget to check that argc == 2 before trying to open the file.
Always check return statuses, especially from 'known to fail' function such as fopen(). And print the name that you're opening - it would have told you a lot about your problem - after checking that argc is set to a value you expect.
You access two elements after the last element of argv. You also don't check the return value of fopen(), both could cause the segfault.
Related
I'm writing a code that appends text to a file.
It uses fopen in the beginning of WriteToFile so even if the file does not exist, it creates it.
But, what happens when I enter no file at all? no arguments at all? Just ./a.out?
Segmentation fault.
I don't know why, it seems to me I did everything fine to avoid any problems.
int main(int argc, char **argv)
{
char file_name[30] = "file.txt";
printf("%s",file_name); /* for debugging : doesn't print it */
if (0 != argc)
{
strcpy(file_name, argv[1]);
}
WriteToFile(file_name);
}
OR
(in case I can't really put a string literal into char array):
char file_name[30];
if (0 == argc)
{
strcpy(file_name, "file.txt");
}
else
{
strcpy(file_name, argv[1]);
}
For both of the cases i'm getting
Segmentation fault (core dumped)
if (0 != argc)
The argc value is normally(a) the count of arguments including the program name. Hence, running ./a.out will have an argc of one rather than zero. And, since argv[argc] is usually NULL, dereferencing it is not going to end well :-)
If you want to ensure another argument is available, you can use:
if (argc > 1) { // Have both argv[0] AND argv[1].
nowSafeToUse(argv[1]);
}
In more detail, the C11 standard states:
If they are declared, the parameters to the main function shall obey the following constraints:
The value of argc shall be nonnegative.
argv[argc] shall be a null pointer.
If the value of argc is greater than zero, the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment. If the host environment is not capable of supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the strings are received in lowercase.
If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name; argv[0][0] shall be the null character if the program name is not available from the host environment. If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc-1] represent the program parameters.
The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.
As an aside regarding this line:
printf("%s",file_name); /* for debugging : doesn't print it */
If this is not printing, it's probably because standard output is line buffered (default if it's determined to be an interactive device, otherwise fully buffered).
By not outputting a \n at the end, the characters are probably still sitting in a buffer somewhere, ready to be written. The crash will probably kill off the process without flushing the buffer. So a simple solution may be just to use one of:
printf("%s",file_name);
puts(file_name);
As another aside, you're going to get into trouble if the filename you enter is larger than 29 characters since it will overflow file_name, allowing for the \0 at the end as well.
A better approach may be just to use either your default string or argv[1] directly (without copying), something like:
int main(int argc, char **argv) {
char *file_name = (argv > 1)
? argv[1]
: "file.txt";
printf("%s\n", file_name); // for debugging : probably does print it :-)
WriteToFile(file_name);
}
(a) Not required by the standard since it allows for implementation-specific differences, but it's the usual case. Specifically, the phrase:
... which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment.
pretty much means it can do whatever it wants :-)
A related answer (though a non-duplicate question) can be found here.
When argc is 1, argv is treated as an array of 2 pointers to char. The first is a valid pointer (typically to the program name), the second is NULL.
argv[1] accesses the second element of argv. With no arguments supplied, argc will be 1 and argv[1] will be NULL. You're therefore dereferencing a NULL pointer.
The condition 0 != argc should instead be argc >= 2 or argc > 1, and the condition 0 == argc should be argc < 2 or argc <= 1.
You have to account for the program's name so you should write if (argc >= 2) instead. See the man
The value of the argc argument is the number of command line arguments. The argv argument is a vector of C strings; its elements are the individual command line argument strings. The file name of the program being run is also included in the vector as the first element; the value of argc counts this element. A null pointer always follows the last element: argv[argc] is this null pointer.
argv[1] means index 1 but in C you start at index 0.
Fixed code
int main(int argc, char **argv)
{
char file_name[30] = "file.txt";
printf("%s",file_name); /* for debugging : doesn't print it */
if (argc >= 2)
strcpy(file_name, argv[1]);
else
return 1; // exit program with error code.
WriteToFile(file_name);
return 0; // exit with success
}
So, I noticed that my argc is always 1 as I will always get the message Error: missing command line arguments!, but as stated in code I am using argv[1] and argv[2] to read the files names.
Shouldn't automatically argc be 3 in this case, and to be able to pass that error?
Notes:
If I am not using if (argc < 2) statement, after I enter the name for the output file my program crushes.
For the input file I already have this one created in the project folder, so I just enter the name of that file.
This is the code:
#include <stdio.h>
#include <stdlib.h>
FILE *IN, *OUT;
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf("Error: missing command line arguments!\n");
return 1;
}
printf("Enter the name of the file with the input data: ");
scanf("%s", argv[1]);
printf("\nEnter the name of the file for the output data: ");
scanf("%s", argv[2]);
IN = fopen(argv[1], "r");
OUT = fopen(argv[2], "w");
fclose(IN);
fclose(OUT);
return 0;
}
You're complete mis-understanding the purpose of argc and argv. They are supposed to receive the supplied command line argument (program parameters) before the program startup, not supposed to hold the scannned input at runtime.
Quoting C11, chapter ยง5.1.2.2.1,
If they are declared, the parameters to the main function shall obey the following
constraints:
โ The value of argc shall be nonnegative.
โ argv[argc] shall be a null pointer.
โ If the value of argc is greater than zero, the array members argv[0] through
argv[argc-1] inclusive shall contain pointers to strings, which are given
implementation-defined values by the host environment prior to program startup. The
intent is to supply to the program information determined prior to program startup
from elsewhere in the hosted environment.
and
If the value of argc is greater than zero, the string pointed to by argv[0]
represents the program name; argv[0][0] shall be the null character if the
program name is not available from the host environment. If the value of argc is
greater than one, the strings pointed to by argv[1] through argv[argc-1]
represent the program parameters.
To elaborate, when a program is invoked like
./a.out three total arguments
then, in your program
argc will be 4
argv[0] will be ./a.out
argv[1] will be three
argv[2] will be total
argv[3] will be arguments
argv[4] will be NULL (see the property for argv[argc] above)
(To generalize, argv[1] - argv[argc-1] will hold the supplied arguments, argv[argc] will be NULL)
You don't need to explicitly scan the input, those values will be populated from the host environment.
On the other hand, you cannot just invoke the program like
./a.out
and exptect argc to be 3 (or any other value, other than 1, for that matter) and argv[1] - argv[n-1] to be valid because at compile-time the invokes program has no way to know that you plan to supply some values at runtime. It's not clairvoyant.
If someone can help me get past this roadblock that would be amazing. I am trying to open a text file called "inputfile.txt" and I can not! Every example I have looked at has worked fine, but when I try to use it, the file returns null and I get a segmentation fault.
Note, this is prior to error checking
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *inputPtr;
inputPtr = fopen(argv[2], "r");
fclose(inputPtr);
}
I realized that I "goofed" slightly, when I first created the text files on my desktop I titled it "inputfile.txt", but it was saved as "inputfile.txt.txt" as odd as that is!
Well the first big problem is that you do not check the value of argc. This value is set to the number of arguments that were passed to the programm. By default argc is at least 1, because 1 argument is always passed. If you pass any additional arguments, argc must be greater than 1. In your case, i guess it should be 2.
The second problem comes from the first. The numbering of array elements in C starts from 0, so if your programm accepts argc arguments, argv which keeps the arguments will have argc elements, BUT!!! the last element will have an index of argc-1. By default, if no additional arguments were passed only argv[0] exists and it is the name of the programm, it is also always passed, hence argc is always at least 1.
In your case, if argc==2, then argv[2] simply does not exist, only argv[0], and argv[1] exist. And when you pass one argument to the programm, it will be kept in argv[1]. That means that this line inputPtr = fopen(argv[2], "r"); should be changed to this inputPtr = fopen(argv[1], "r");. Also there should be a check of argc at the beginning of the programm. soome thing along the lines of
int main(int argc, char *argv[])
{
if(argc!=2)
{
printf("Wrong number of arguments\n");
return -1;
}
.....
}
before accessing anything beyond argv[0] (which is always available)
the code must check the value of argc to assure the command line parameter actually exists.
Note; in C, array indexs start from 0 through (count of array entries -1).
So if argc is 2, then there is only one command line parameter and:
argv[0] is the executing program name
argv[1] is the first parameter.
argv[2] is a NULL pointer.
so using argv[2] is accessing address 0 and will result in
undefined behaviour
lead to a seg fault event
I am trying to validate user input from the command line with argc and argv but am running into a segmentation fault and am not sure why.
I want to validate the user has entered a positive int (so argc =2 and argv is positive).
Here is my code:
int main (int argc, string argv[])
{
int k = atoi(argv[1]);
if (argc != 2 && k <1)
{
return 1;
}
}
The k < 1 part of my code seems to be working fine, but I get segmentation errors every time I try to run without the program name and an argument (agrc !=2).
EDIT:
More clear description of the error handling problem:
If I run ./myprogram -2
then I get my return 1 as expected.
If I run ./myprogram hjdksfhdsk
then I get my return 1 as expected.
If I run ./myprogram
then I get a segmentation fault.
It is this behaviour that makes me think my handling of the argc value is at fault, but I am not sure why I cannot just test argc !=2.
This is incorrect, since in C string is not a built-in type (and is not a standard type defined in some standard header - notice that C++ has std::string defined in its <string> standard header).
The signature of main has to be
int main(int argc, char**argv);
The convention is that argv[argc] is the null pointer, and the argc pointers from argv[0] to argv[argc-1] are non-null pointers to null-terminated strings.
Notice that (at least on Linux and Posix systems) program arguments are not user input to the program. The shell has been given a command line as input and has expanded that command line into program arguments. Your program could later read some input, e.g. with scanf.
You cannot convert a NULL pointer with atoi, so you should check argc before doing the conversion.
int main(int argc, char**argv) {
if (argc!=2) {
fprintf(stderr, "%s needs two arguments\n", argv[0]);
exit(EXIT_FAILURE);
};
int k = atoi(argv[1]);
if (k<=0) {
fprintf(stderr,
"%s wants a positive first argument, but got %s\n",
argv[1]);
exit(EXIT_FAILURE);
}
// now do the real thing
}
BTW, I believe that (at least on Linux or Posix system) a program should accept the --help argument per the GNU coding standard. I suggest you to use getopt (notably getopt_long) or argp to parse program arguments.
At last, compile with all warnings and debug information (e.g. with gcc -Wall -g) and learn how to use the debugger (e.g. gdb).
Your main should be
int main(int argc, char*argv[])
And do the check before using on atoi on argv[1]
Also all paths should return a value. Bung return 0; at the end
As others have noted string is not a base type. However since you are getting results in one case your segmentation fault has to do with the atoi on argv 1. In c arrays are 0 based so you're trying to convert uninitialized memory. Use the argc test before the atoi.
I'm trying to use "echo FileName.txt | a.c" in terminal and read the data from the file into a array i got in a header file, but the code I have so far is just giving me a infinite loop. I tried storing the info in a local array also but still the same result.
main(int argc, char *argv[]) {
extern char test[];
FILE *fp;
int i = 0;
int c; // was char c; originally
if (argc == 1) {
fp = stdin;
} else {
fp = fopen (argv[1], "r");
}
while ((c = getc(fp)) != EOF) {
test[i] = c;
printf("%c", test[i]);
i++;
}
}
(1) Change variable c to an int so it recognizes EOF.
(2) Don't increment i before your printf or you will be printing junk.
Not sure what you are trying to accomplish with the echo thing.
NOTE: I'm assuming that your program is intended to do what the code in your question actually does, namely read input from a file named by a command-line argument, or from stdin if no command-line argument is given. That's a very common way for programs to operate, particularly on Unix-like systems. Your question and the way you invoke the program suggest that you're doing something quite different, namely reading a file name from standard input. That's an unusual thing to do. If that's really your intent, please update your question to clarify just what you're trying to do.
Given this assumption, the problem isn't in your program, it's in how you're invoking it. This:
echo FileName.txt | a.c
will feed the string FileName.txt as input to your program; the program has no idea (and should have no idea) that it's a file name.
The way to pass a file name to your program is:
a.c FileName.txt
Or, if you want to read the contents of the file from stdin:
a.c < FileName.txt
(In the latter case, the shell will take care of opening the file for you.)
You could read a file name from stdin, but it's rarely the right thing to do.
A few other points (some already pointed out in comments):
An executable file probably shouldn't have a name ending in .c; the .c suffix indicates a C source file.
You should declare main with an explicit return type; as of C99, the "implicit int" rule was removed, and it was never a particularly good idea anyway:
main(int argc, char *argv[]) { /* ... */ }
You're reading the entire contents of the input file into your test array. This is rarely necessary; in particular, if you're just copying an input file to stdout, you don't need to store more than one character at a time. If you do need to store the contents of a file in an array, you'll need to worry about not overflowing the array. You might want to abort the program with an error message if i exceeds the size of the array.
See also the rest of the advice in Jonathan Leffler's comment; it's all good advice (except that I think he misunderstood the purpose of your test array, which you're using to store the contents of the file, not its name).