Why am I segfaulting? - c

I'm very new to C, I am attempting to read the contents of one file character by character and output them to the stream. But even with my fopen() command commented out I receive segfault (core dumped).
I must run a command: ./a.out < testWords.in > myOut.txt to execute my file properly.
Here is what I have so far:
#include <stdio.h>
void main(char *fileName[])
{
printf("filename is %s.\n",fileName[0]);
//Get file based on a string inputed
FILE *fp=fopen(fileName[0],"r"); //Fetches our file as read only
char ch;
int lineCount = 0;
int wordCount = 0;
int charCount = 0;
//Failed to find/open file. NULL character.
if (fp == 0) printf("Woops! Couldn't open file!\n");
//While not at end of file, grab next char.
else while( (ch=fgetc(fp)) != EOF)
{
if (ch == '\n') //on newline
{
//Prints (charCount,wordCount)\n lineCount:
printf("(%d,%d)%c%d:",charCount,wordCount,ch,lineCount);
charCount = 0;
lineCount += 1;
}
else printf("%c",ch); //mirrors char.
}
fclose(fp); //Closes file (gotta be tidy!)
}

You can't just invent a way to call main. You need to use one of the standard ways, like this:
int main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Missing filename\n");
return -1;
}
FILE *fp = fopen(argv[1], "r");
// ...
}
And note that argv[0] contains the program name (if available; if not it contains an empty string).
Your program segfaulted because you received the int argc argument into your char *filename[] parameter. If you ran the program with a single command line parameter, the value passed in as the first argument would have been 2, which is not a valid pointer value. The expression filename[0] dereferences that address and causes a segfault.

Any time you get a segfault in C, you should smell a bad pointer or address in an argument list. In this particular case., the signature of main is always int main(int argc, char** argv). Yours isn't.
What you want is
int main(int argc, char ** argv) {
...
FILE * fp = fopen(argv[1]); // Quiz: why argv[1]? What's argv[0]?
You're getting away with it in the compiler because, basically, luck.
I also notice in your example call, there's actually no argument in the argument list, because you're using redirection.

Use:
int main(int argc, char* argv[])
And use argv[1] as fileName.
Main function must receive always that two parameters.

Related

Can I save a .txt file passed as a command line argument to a char array in C?

I'd like to save a .txt file that I am passing as an argument into some sort of datatype. For example, if my command was ./projexec -c "some text" filename.txt, my goal is to copy the contents of filename.txt(argv[3]) into a char array. Is this possible, if so how?
int main(int argc, char *argv[]) {
int i;
FILE *fp;
char txtfile[];
for(i=0; i<argc; i++) {
if(argc>1 && argv[3] !=NULL) {
fp=fopen(argv[3],"r");
}
else {
printf("There is no .txt file in this argument.");
}
}
UPDATE: fread did the trick!
#define size 1000
int main(int argc, char *argv []) {
int i;
FILE *fp;
char argtxt[]= ".txt";
char txtfile[size];
size_t br;
for(i=0; i<argc; i++){
if(argc > 1 && strstr(argv[i],argtxt)!=NULL){
fp=fopen(argv[i],"r");
br=fread(txtfile,sizeof(txtfile),size, fp);
printf("file copied.\n");
}
}
printf(txtfile);
}
I would recommend reading about the "mmap" system call.
You need to open a file using the "open" system call,
then call "mmap" on it, which returns a pointer to a buffer (created for you by the system) so you can just treat it like a very long string.
Lines are separated with "\n" and make sure you have opened the file with writing permissions if you are planning on using "strtok" on the string.
This is due to the fact that "strtok" rewrites the delimiter to a null terminator.

Open file using commandline

I'm working on an assignment and I have to open a file from command line upon executing the program.
Example:
program.exe file.txt
However that is not working at all for me. Can someone please tell me what I'm doing wrong? This is the first time I'm working with taking a file as a parameter.
int main(int argc, char **argv) {
int value;
value = fileRead(argv[1]);
}
int fileRead(char argv[]) {
int value;
FILE *fp;
fp = fopen(argv[1], "r");
if (fp) {
fscanf(fp, "%d", &value);
} else {
fprintf(stderr, "Failed to open file!\n");
}
return value;
}
You're mixing up a character and a string. You pass argv[1] to fileRead as argv. Then in fileRead, you do argv[1] again. This effectively does argv[1][1], which just gives the second character of the string. You need to either remove the [1] from in main and then change the argument type, or remove the [1] from fileRead.

Creating a File to array function

Currently I have the argc, argv and temp pieces placed in to be passed, and when I compile it returns no errors, but when I call the function later in the program and pass it a char array. It returns a stack dump. From what I have learned so far arrays cannot be passed back from a function and that is why I have passed the pointers.
int In2File(int argc, char *argv[], char *temp[] ){
if (argc == 2) { //open file
FILE *user_file;
user_file = fopen(argv[1], "r");
if (user_file == NULL) {
printf("No data was found.\nEnd(Error 1)");
exit(2);
}
else {
int g = 0;//temp counter to load
char c = 0;
while ((c = fgetc(user_file)) != EOF && g <= tmplng - 1) { //Used Fgetc instead of fgets because Fgetc allows me to read
*temp[g] = c; //until the end of the file and read each character. Even if there is an \n character.
g++; // The second g < tmplng-1 is used to make sure that the \0 can be placed into the array.
}
printf("%s\n", temp);
fclose(user_file);//Closed the txt file that was loaded by user in args(1)
printf("\nFile Loaded.\n");
}
}
else if (argc > 2) { // Will exit if arguments are greater than 2.
printf("Format: %s 'filename'", argv[0]);
exit(1);
}
else {
printf("File not provided. Enter information:\n");//If the user doesnt provide a file allow manual input.
fgets(*temp, tmplng, stdin);
}
}
In2File(argc,argv,temp);
Anyone have an idea as to where I went wrong with this function? I read a few similar posts but they were for C++ and Python. Which I havent learned C++ as yet and python is different to this beast called C.
Edit:
const int tmplng = 1000; //The only variables needed
char temp[tmplng]; //
char temp2[tmplng]; //
printf("Starting....\n"); //Used for testing debugging.
The third parameter to the function doesn't match what the function is expecting. You're passing in a char [] (which decays to a char *), while the function expects char *[] (equivalently char ** as a function parameter).
The definition of the third parameter doesn't match how you intend to use it, which is as a character array.
Get rid of the extra level of indirection on the parameter, and adjust the function accordingly.
int In2File(int argc, char *argv[], char temp[] ){
...
while ((c = fgetc(user_file)) != EOF && g <= tmplng - 1) {
temp[g] = c;
g++;
}
This declaration of temp:
char temp[tmplng];
... does not go with this call ...
In2File(argc,argv,temp);
... to this function ...
int In2File(int argc, char *argv[], char *temp[] );
The function expects its third argument to be a pointer to a pointer to char *, but what it receives is a pointer to char. When it then tries to assign the character read ...
*temp[g] = c;
That attempts to interpret the gth element of temp (itself interpreted as a char **) as a char *, to dereference that pointer, and to assign c to that location. That is highly unlikely to be a valid memory access.
It looks like you want to declare the third argument of In2File as either char *temp or char temp[], which are equivalent, and to write to it as temp[g] = c.
ALSO, as an aside, note that your
printf("%s\n", temp);
is problematic because you do not ensure that temp is null-terminated. And inasmuch as you support reading up to the very last byte, you don't have room to terminate it.
As numerous folks are pointing out in the comments, your code would be much easier to understand if you employed "early exit" for your error conditions.
It would also be a better separation of concerns to have main deal with the program arguments and let In2File just deal with a file pointer.
int main( int argc, char *argv[] ) {
FILE *fp;
if( argc == 2 ) {
fp = fopen(argv[1], "r");
if ( fp == NULL ) {
fprintf(stderr, "Couldn't open %s: %s", argv[1], strerror(errno));
exit(2);
}
}
else if( argc > 2 ) {
fprintf(stderr, "Usage: %s <optional filename>", argv[0]);
exit(1);
}
else {
fp = stdin;
}
char *lines = In2File(fp);
printf("%s\n", lines);
free(lines);
}
Note that stdin is a file pointer just like anything you opened with fopen. I've also used strerror and errno to provide the reason the file didn't open.
Now In2File just takes a file pointer. Also note that I have it returning the content, not passing in a preallocated array. This is because when reading from input you never know how much input you're going to get. You either must stop reading before you run out of space, or allocate more memory. You can't reallocate stack memory, so it's best to let In2File control allocating memory. It also avoids having to pass around a global variable.
Once that's done, In2File becomes much simpler.
static char *In2File( FILE *fp ){
size_t read_size = 1024;
/* Don't forget space for null */
char *content = calloc( read_size + 1, sizeof(char) );
fread( content, sizeof(char), read_size, fp );
return content;
}
Rather than step through a character at a time, I've used fread to read a block from the file not larger than the amount I've allocated. Memory reallocation is a topic for another time.

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.

How do I define and pass in a file name to fopen() from command line?

I have the following program that writes a user's input to a file. Currently the file to be written to is predefined; however, I was wanting allow the user to define the file name from command prompt. What would be the best way to add this functionality? I am having trouble getting my head around how I would make the string entered by the user an argument in the fopen() function. Should I use scanf() or create another getchar() while loop store the chars in an array and then create a variable as the argument of fopen() or something?
#include <stdio.h>
int main()
{
char c;
FILE *fp;
fp = fopen("file.txt", "w");
while ((c = getchar()) != EOF)
{
putc(c, fp);
}
return 0;
}
That's what the arguments to main are for:
#include <stdio.h>
int main(int argc, char **argv)
{
char c;
FILE *fp;
if (argc >= 2)
fp = fopen(argv[1], "w");
else fp = fopen("file.txt", "w");
while ((c = getchar()) != EOF)
{
putc(c, fp);
}
return 0;
}
If you followed this, you might wonder what is in argv[0]. That's where the program name is. Some operating system environments put the full path to the executable file there. Others put only the program name. Others still put what was typed.
For the command ../../bin/someprogram
on Windows, argv[0] is "C:\\Documents and Settings\\User\bin\\someprogram.exe"
on Linux/bash, argv[0] is ../../bin/someprogram
on Ultrix/csh, (I think) argv[0] is /home/username/bin/someprogram
Use argc and argv
#include <stdio.h>
int main(int argc, char **argv)
{
char c;
FILE *fp;
if(argc < 2){
printf("Usage : ./a.out <filename>");
exit(0);
}
fp = fopen(argv[1], "w");
while ((c = getchar()) != EOF)
{
putc(c, fp);
}
return 0;
}
Define main like this:
int main(int argc, char *argv[]) {
And then use argv: an array of the command-line arguments. argv[0] is the name of the command as entered at the command line, argv[1] is the first argument.
fp = fopen(argv[1], "w');
You probably want to check that argc > 1 to avoid an out-of-bounds array access.
There are many functions to read in strings; fgets and scanf, for example. The problem is that you need to know the max number of characters that you want to read in before-hand. If this is ok for you, then use one of those. If not, then you'll have to write your own function to read in a dynamic string, like here.

Resources