I am writing a program that should be able to take command line parameters.
Basically, the user must be able to specify a file name through command prompt while calling the program. i.e the program should be able to take in a parameter like:
doCalculation -myOutputfile.txt. where doCalculation is the name of my program and myOutputfile is the file I want my results written to (i.e output the results of my calculations to the specified file name).
So far I can call my function through the command prompt. I am not sure how to get my program to write to the filename specified (or create this file if it does not exist already).
My code is as follows:
int main(int argc, char *argv[])
{
FILE* outputFile;
char filename;
// this is to make sure the code works
int i = 0;
for (i = 0; i < argc; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
//open the specified file
filename= argv[i];
outputFile = fopen("filename", "r");
//write to file
fclose(outputFile);
}
So a couple things I noticed...
If you want to write to the file, use "w" for write-mode instead of "r" for read-mode when opening the file.
You declared filename as a single character rather than a pointer to a string (char *). Making it a pointer will allow filenames with a length > 1 (array of chars rather than a single char).
As Ashwin Mukhija mentioned, you're using i after the for loop set it to 2, when infact you want the 2nd (index 1) argument.
You had the filename argument in the open() function as a literal "filename" rather than your filename variable.
See if this code helps solve your problem, (I also tossed a fprintf() in there to show you how you can write to the file).
Cheers!
int main(int argc, char *argv[])
{
FILE* outputFile;
char* filename;
// this is to make sure the code works
int i = 0;
for (i = 0; i < argc; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
//saftey check
if(argv[1])
{
filename = argv[1];
//open the specified file
outputFile = fopen(filename, "w");
fprintf(outputFile, "blah blah");
//write to file
fclose(outputFile );
}
return 0;
}
Related
Good afternoon, Old man trying to learn new tricks here,
I have been given an assignment that I am trying to work my way through but I am stuck as I don't fully understand the argv[]
I have 4 files I want to read from and eventually use malloc and realloc but thats further down.
My initial plan was to try read one file and get it onto the command line. I had it opening but made that many changes that now I'm lost.
Think my problem lies with argv[4] as i dont understand it, when I put 4 it goes into theloop and errors but with 1 it just bombs out.
If someone can point me in the direction I am going wrong here it would be great
Thanks
struct Person { char lname[20]; char fname[20]; int id; };
int i, N;
struct Person *student;
int main(int argc, char *argv[])
{
FILE *outputfile;
printf("Please enter the name of the file to open: ");
scanf("%s", argv[4]);
outputfile = fopen(argv[4], "r") ;
if (outputfile==NULL){
perror(argv[1]);
fprintf(stderr,"Error while opeining file\n");
exit(-1);
}
You don't have to use argv[]. Argv is an array of strings that store the arguments passed in when running the executable. If you run the executable like this: ./a.out, then argv only contains one element, which is the path of the executable itself. If you run the program like this, and you try to access argv[4], it does not give you an error, but if you debug it using GDB, it will output the following: warning: Invalid parameter passed to C runtime function.
You could pass in a file on the command line like this: ./a.out yourfile.txt. In this case, argv[0] will be the path of the executable a.out, and argv[1] will be the string "yourfile.txt".
It might be easier to completely drop the use of argv and store the user input for the filename in a string. You can then pass that string as an argument to fopen. This would look something like this:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char fileName[30];
char ch;
printf("Please enter a file name\n");
scanf("%s", fileName);
FILE *outputFile = fopen(fileName, "r");
if(outputFile == NULL) {
printf("Could not open %s\n", fileName);
exit(-1);
}
}
Use constants (NAME_LEN) instead of hard-coding magic values.
Prefer multiple lines for your struct. It's easier to read and version control systems prefer lines for diffs.
Avoid global variables.
Do a boundary check using argc (count of elements in argv) before you read argv. argv[0] is the name of your program, argv[1] is the first argument.
Treat argv as read-only, i.e. don't do scanf("%s", argv[4]).
Prefer to initialize variables instead of declaring and assigning a value separately. It's easy to forget setting a variable before use which leads ot undefined behavior. Initialization might be faster, too.
Your file handle is called outputfile but with fopen() you use the mode of r for reading. Either mode should be w or you want to change the variable name to inputfile.
#include <stdio.h>
#include <string.h>
#define NAME_LEN 20
struct Person {
char lname[NAME_LEN];
char fname[NAME_LEN];
int id;
};
int main(int argc, char *argv[]) {
char filename[FILENAME_MAX];
if(argc > 4) {
strcpy(filename, argv[4]);
} else {
printf("filename? ");
fgets(filename, FILENAME_MAX, stdin);
filename[strcspn(filename, "\n")] = '\0';
}
FILE *outputfile = fopen(filename, "w");
if(!outputfile) {
// ...
}
fclose(outputfile);
}
and you would run your program with either:
$ ./a.out dummy dummy dummy output.txt
or
$ ./a.out
filename? output.txt
It sounds as if you are expected to provide 4 file names as command line parameters. In which case you should be doing this:
#include <stdio.h>
int main (int argc, char *argv[])
{
const int files = 4;
if(argc != files+1)
{
printf("Usage: myprog file1 file2 file3 file4");
return 0;
}
FILE* fp [files];
for(int i=0; i<files; i++)
{
fp[i] = fopen(argv[i+1], "r");
...
}
...
}
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.
I have an issue with writing strings into a txt file. My lines get overwritten every time. I use
gcc -Wall -o filename filename.c to compile and ./filename 10 Berlin cat resultat.txt to execute.
The txt file always has just one line (the last one) how can I save all the records.
I have a CSV file with city names and a number of residents, I need to filter for the City name and a minimum of residents.
What I tried so far:
.....
void write_file(char *result[], int len) {
FILE *fp = fopen("resultat.txt", "w");
if (fp == NULL){
perror("resultat.txt");
exit(1);
}
for (int i=0; i<len; i++) {
fprintf(fp, "%s\n", result[i]);
}
fclose(fp);
}
int main(int argc,char **argv) {
int anzahl = atoi(argv[1]);
char *string_array[100];
char *erste_zeile;
erste_zeile = (char *) malloc(1000 * sizeof(char));
char staedte[MAX_LAENGE_ARR][MAX_LAENGE_STR];
char laender[MAX_LAENGE_ARR][MAX_LAENGE_STR];
int bewohner[MAX_LAENGE_ARR];
int len = read_file("staedte.csv", staedte, laender, bewohner);
for (int i = 0; i < len; ++i){
if (strcmp(argv[2],laender[i])==0 && anzahl < bewohner[i]){
snprintf(erste_zeile, 100,"Die Stadt %s hat %d Einwohner\n",staedte[i],bewohner[i]);
string_array[0] = erste_zeile;
// counter++;
write_file(string_array,1);
}
}
free(erste_zeile);
return 0;
}
Using the write_file() function outside of the for loop gives me null values. If anybody has an idea how to optimize the code please leave a comment or answer.
Each time you use FILE *fp = fopen("resultat.txt", "w"); what this does is delete the existing file and create a blank file for writing. What you're looking for is FILE *fp = fopen("resultat.txt", "a"); //a not w!. This will open the existing file and append content. If a file does not exist, one will be created. See this reference.
"w" -
Creates an empty file for writing. If a file with the same name already exists, its content is erased and the file is considered as a new empty file.
"a" -
Appends to a file. Writing operations, append data at the end of the file. The file is created if it does not exist.
Also heed #Serge's advice about not opening the file for each record. Just open it once in the main and use the file handle to write to it. To make your current code work, you can do this:
void write_file(char *result[], int len) {
FILE *fp = fopen("resultat.txt", "a");//open for append
if (fp == NULL){
perror("resultat.txt");
exit(1);
}
for (int i=0; i < len; i++) {
fprintf(fp, "%s\n", result[i]);
}
fclose(fp);
}
I have some problem with fopen() function in C.
I'am parsed directory and put all the paths to char array(char**). After that i should to open all these files. And...
fopen returns "No such file or directory" for some files. And I Am really don't understand, why.
All paths are right. I checked it.
I have all privileges to
open these files.
If I copy path to file from error log and try
to open only this file via my programm - it works.
Others
programms don't work with these files(i think).
What can I do wrong?
int main(int argc, char *argv[]){
char** set = malloc(10000*sizeof(char*));
char* path = argv[1];
listdir(path, set); /* Just parse directory. Paths from the root. No problem in this function. all paths in the variable "set" are right */
int i=0;
while(i<files){ /* files is number of paths */
FILE* file = fopen(set[i++],"rb");
fseek(file, 0L, SEEK_END);
int fileSize = ftell(file);
rewind(file);
/*reading bytes from file to some buffer and close current file */
i++;
}
}
You increments 'i' twice. May be mistakenly?
You can get file size w/o open it using stat().
ftell() returns "long", don't cast it in "int" as it can be shorten and you loose correct value.
Try this code:
#include <stdio.h>
#include <sys/stat.h>
/* example of listdir, replace it with your real one */
int listdir(const char *path, char *set[])
{
set[0] = "0.txt";
set[1] = "1.txt";
set[2] = "2.txt";
set[3] = "3.txt";
set[4] = "4.txt";
return 5;
}
int main(int argc, char *argv[]) {
int files;
char *path = argv[1];
char **set = malloc(1000 * sizeof(char *));
files = listdir(path, set);
for (int i = 0; i < files; i++) {
struct stat st;
stat(set[i], &st);
printf("FileSize of %s is %zu\n", set[i], st.st_size);
}
free(set);
}
(I am guessing you are on some Posix system, hopefully Linux)
Probably your listdir is wrong. FWIW, if you use readdir(3) in it, you need to concatenate the directory name and the file name (with a / in between, perhaps using snprintf(3) or asprintf(3) for that purpose).
But surely,
FILE* file = fopen(set[i++],"rb"); ////WRONG
is doubly wrong. First, you are incrementing i++ twice (and here it is too early). Then, you should read fopen(3) and handle the failure case, at least with:
char* curpath = set[i];
assert (curpath != NULL);
FILE* file = fopen(curpath, "rb");
if (!file) { perror(curpath); exit(EXIT_FAILURE); };
testing the result of fopen against failure is mandatory. Notice that I am passing the same curpath to perror(3) on failure.
You may also want to check that your current working directory is what you expect. Use getcwd(2) for that.
Use also strace(1) (on Linux) to understand what system calls are done by your program.
So i have implemented the game of life and now have to put every new generated field into a gif or pbm and at the end with a command I create an animated gif.
The below function is given but I don't get the first parameter, a pointer const char? I see in the function that is the filename, but how do I write that, I'm really confused.
static int write_pbm_file(const char *fn, struct game_field *gf) {
int i, j;
FILE *fp;
fp = fopen(fn, "w+");
if(!fp){
printf("unable to open '%s' - '%s'\n", fn, strerror(errno));
return -1;
}
fprintf(fp, "P1\n");
fprintf(fp, "%c\n", gf->length);
fprintf(fp, "%c\n", gf->length);
for(i = 0; i < gf->length; i++)
for(j = 0; j < gf->length; j++)
fprintf(fp, "%c\n", gf->field[i][j] == 0 ? 48 :
gf->field[i][j] == 1 ? 219 : 197);
fclose(fp);
return 0;
}
That's the code where I get to the above function:
while( iterations > 0 ) {
write_pbm_file(..., pstField);
pstField = game_iteration(pstField);
iterations--;
}
What should I write to create this files? Please help
Thank you!
A pointer to non-changing character data can most easily be produced by just using a string literal:
write_pbm_file("life.pbm", pstField);
You probably want to change the filename for each iteration, though. Maybe something like this:
char filename[100];
while(...)
{
sprintf(filename, "life-%03d.pbm", iteration);
write_pbm_file(filename, pstField);
This re-uses your iteration counter (which counts backwards), so the first file to be written will have the largest number. I added 0-padding to three decimal digits, of course I don't know how many iterations you need.
The parameter fn is simply a path to a file. On a unix system you might write "/home/someuser/somefile.ext", on windows you'd write "C:\\Some\\Path\\somefile.ext"
You could also make it configurable through the program arguments, using argv[1] or the like. E.g:
int main(int argc, char** argv) {
if (argc < 1) exit(1);
char* filename = argv[1];
...
while( iterations > 0 ) {
write_pbm_file(filename, pstField);
pstField = game_iteration(pstField);
iterations--;
}
}
Assuming you have a game_field field, writing it out to, say, /home/you/foo.pbm would be
write_pbm_file("/home/you/foo.pbm", &field);
const char * is a type that string literals, char *, const char [] and char [] decay to.