I am using Code::Blocks and have set the command-line arugments via the IDE. I have also opened the executable with the proper argument and I can't manage to get a non-NULL on fopen() return. I've tried hard-coding the filename also with no success. The platform is Windows XP SP3.
The first is the one that fails, when i hardcoded it i used double backlash. Also i never knew if the second works because i never managed to start the process by opening the first one.
Obviously i put the text file in the same directory that the executable and rebuilt the executable many times, but it still doesn't work.
EDIT: I added the perror("fopen"); line in the if(finput==NULL) block. This is the output.
http://prntscr.com/h71pa
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define first_part_url "[url=http://magiccards.info/query?q="
#define second_part_url "&v=card&s=cname]"
#define end_bracket "[/url]\n"
#define output_file_prefix "output_"
char* get_card(FILE* finput);
int main(int n, char* arguments[])
{
FILE* finput;
FILE* foutput;
short int counter;
char* output_filename;
char* finalstring;
for(counter=1; counter<n; counter++)
{
finput=fopen(arguments[counter], "r");
if (finput==NULL)
{
printf("Unable to open ");
puts(arguments[counter]);
perror("fopen");
break;
}
strcpy(output_filename, output_file_prefix);
strcat(output_filename, arguments[counter]);
if((foutput=fopen(output_filename, "w"))==NULL)
{
printf("There was an error while trying to open ");
puts(arguments[counter]);
printf(" .\n");
break;
}
while(!feof(finput))
{
finalstring=get_card(finput);
fputs(finalstring, foutput);
while(((fgetc(finput))!='\n')||feof(finput));
}
printf("Autocarding ");
puts(arguments[counter]);
printf(" was a success.\n");
fclose(foutput);
}
if(finput!=NULL)
{
fclose(finput);
free(finalstring);
}
return 0;
}
char* get_card(FILE* finput)
{
char* currentcard;
char* finalstring;
currentcard=(char*)malloc(sizeof(char)*150);
fgets(currentcard, 150, finput);
/* Allocates the exact amount of space needed for the final string*/
finalstring=(char*)malloc(sizeof(char)*(strlen(first_part_url)+strlen(second_part_url)+strlen(end_bracket)+strlen(currentcard)));
/* Get all the final forum link together*/
strcat(finalstring, first_part_url);
strcat(finalstring, currentcard);
strcat(finalstring, second_part_url);
strcat(finalstring, end_bracket);
free(currentcard);
return finalstring;
}
The error you are getting, "No such file or directory" indicates that the file name you're trying to open doesn't exist.
In this case, it's probably because the program's current working directory is not the same as the directory containing the executable file.
This
finput=fopen(arguments[counter], "r");
Will only fail if you do not supply correct filenames (e.g. if there are non-ASCII characters in the names or the names do not include the correct path, fopen() opens files in the current directory if no path is specified in the file name).
This
output_filename=(char*)malloc(sizeof(arguments[counter]));
most likely does not allocate enough space for a name because arguments[counter] is a pointer, and sizeof() of a pointer is not the same as strlen(that_same_pointer) + 1.
This
output_filename=output_file_prefix;
loses the just allocated memory because you are reassigning the pointer output_filename to point to some other place, output_file_prefix ("output_").
After the above this
strcat(output_filename, arguments[counter]);
is likely going to crash your program because this is going to attempt to overwrite a string literal ("output_"), doing which causes undefined behavior per the C standard.
You have to allocate enough cumulative space for the strings that you want to concatenate and you have to concatenate them in the allocated space.
To save you even more trouble, here's another problem:
finput=fopen(arguments[counter], "r");
...
while(!feof(finput))
feof() only works after at least one read from a file. This has been asked ans answered multiple times.
Try changing
for(counter=1; counter<n; ++n)
{
to
for(counter=1; counter<n; ++counter)
It appears the code loops infinitely, therefore it would exhaust the possible elements in your argument array causing a NULL pointer to be returned.
Related
So I've written a program that will take in a information about a dvd (specifically it's postion, IDkey(just some random number) Title, Genre and Year of release), and using a struct it will write that info to a .txt file called "person.txt". I'm positive my code works for the most part but when I go to test it the output received in the .txt file is written in some weird symbol language and not English and quite frankly I have no idea as to why this is. Any explanation on why this is happening would be much appreciated, thanks :)
PROGRAM
#include <stdio.h>
#include <stdlib.h>
// a struct to read and write
struct dvd
{
int fposition;
int fIdKey;
char ftitle[50];
char fgenre[50];
int fyear;
};
int main ()
{
FILE *outfile;
struct dvd input;
// open file for writing
outfile = fopen ("person.txt", "w");
if (outfile == NULL)
{
fprintf(stderr, "\nError opend file\n");
exit (1);
}
printf("Postion: ");
scanf("%d", &input.fposition);
printf("ID Key: ");
scanf("%d", &input.fIdKey);
printf("Title: ");
scanf("%s",&input.ftitle);
printf("Genre: ");
scanf("%s", &input.fgenre);
printf("Year: ");
scanf("%d", &input.fyear);
// write struct to file
fwrite (&input, sizeof(struct dvd), 1, outfile);
if(fwrite != 0)
printf("contents to file written successfully !\n");
else
printf("error writing file !\n");
// close file
fclose (outfile);
return 0;
}
TEST RUN
TEST RUN OUTPUT IN THE .TXT FILE
You are writing these values to the file:
int fposition;
int fIdKey;
char ftitle[50];
char fgenre[50];
int fyear;
But you are displaying the whole file as characters. That kind of works for ftitle and fgenre because they really are characters...though since you don't populate all 50 characters there are some ugly uninitialized characters shown as well. That is easy to fix: just fill the unused characters (as well as the null terminator) with some known character (such as space) before writing to the file, or do not write the unused characters at all. You can use strlen() to find the length of each string and memset() to set the unused characters to a well-known character which is printable.
Next, saving an int and reading it as text is problematic. You need to decide on a single format. Either you write as integers like now, and you read as integers (which means you need a special program to read the file), or you commit to writing only text to the file.
Easiest might be to only write text to the file. You can use fprintf() for that, instead of fwrite(). You can use fprintf() for the character arrays as well, it will automatically write only the "used" part of each string up to the null terminator, skipping all the "garbage" characters.
i'm making na assignment for programming class.
The program is supposed to:
receive a string from command line.
open the current directory and cycle through its entries,
and analyse the entries only if their name starts with
the string that i passed from CMD.
if these entries are regular files,
i need to count all characters except spaces,
and count the number of words that start with a/A.
Here's the code.
int main(int argc,char* argv[])
{
if(argc!=2) //ensures at least an argument is passed.
{
puts("enter one argument.");
exit(EXIT_FAILURE);
}
DIR* folder; //folder abstraction
struct dirent* entry; //entry abstraction
struct stat info; //file's i node info
FILE* file;
int total=0,first=0;
char temp[100];
int res;
folder=opendir("."); //i open the directory
while((entry=readdir(folder))!=NULL) //i cicle through every entry
{
res=strncmp(entry->d_name,argv[1],strlen(argv[1]));
if(res==0) //if entry name begins with string i continue
{
lstat(entry->d_name,&info); //i take file info
if(S_ISREG(info.st_mode)) //i check if it's a regular file
{
file=fopen(entry->d_name,"r"); //i open it
//printf("%s\n",entry->d_name);
while((fscanf(file,"%s",temp))!=EOF) //i parse it
{
if(temp[0]=='a'|| temp[0]=='A')
{
first++;
}
total+=strlen(temp);
}
//now i close the file and print all info
fclose(file);
printf("%s\nthe number words that start with a/A: %i\n",entry->d_name,first);
printf("the amount of characters except spaces is %i\n",total);
total=0;
first=0;
}
}
//now the process will be repeated for the remaining entries
}
return 0;
}
the problem is, the program gets the first entry that starts with the pattern that i passed from CMD, evaluates it correctly, but then
when the stat is called on the second entry, it causes seg fault 11.
if i comment out the lstat, all the entries that match the criteria are recognized, even if no calculation i can't test if it's regular file without lstat...
what is causing the issue, i've been trying stuff for the past two hours, please help me, thanks!
EDIT:
I found the problem, basically the directory I'm working in has binary files of executables.
It turns out that binary files are considered regular files, so when the program opened it to parse it, it parsed one long string that caused buffer overflow on the temp variable. I thought those files were binary and separated from regular.
unexpected seg fault caused by lstat function
With undefined behavior in other parts of code, we do not know the seg fault is caused by lstat. Inclusion of lstat did reveal a problem, yet the true cause may lie elsewhere.
Code has troubles yet it lacks error checking in various places. #Weather Vane
Check function return values
folder=opendir(".");
if (folder == NULL) {
perror("opendir failed);
exit (EXIT_FAILURE);
}
// lstat(entry->d_name,&info);
if (lstat(entry->d_name,&info)) {
perror("lstat failed);
exit (EXIT_FAILURE);
}
file=fopen(entry->d_name,"r");
if (file == NULL) {
fprintf(stderr, "Unable to open <%s> for reading\n", entry->d_name);
exit (EXIT_FAILURE);
}
Limit width
// while((fscanf(file,"%s",temp))!=EOF)
while(fscanf(file,"%99s",temp) == 1) {
if (strlen(temp) == 99) {
fprintf(stderr, "Maximum length word read, longer ones might exist\n");
exit (EXIT_FAILURE);
}
Of course instead of exiting, code cab handle the error in some other way.
Minor: I'd used width types for counting characters.
I came across a confused problem when I program in C
when i use oldPacket.filename = "fallout.jpg" //i have a file called fallout.jpg,and a struct called oldPakcet with an char* type filename
The program ran very well
Now, I decide to let user to in put the filename and also check the existence of the file. I wrote the following function:
bool Searchfile(packet* ptr) {
char userinput[100];
fgets(userinput, sizeof (userinput), stdin); //non terminated input by fgets
userinput[strcspn(userinput, "\n")] = 0;
//printf("%d\n",strlen(userinput));
ptr->filename = userinput + 4;//i skip the first 4 char since the correnct format is ftp <filename>
printf("%s\n",ptr->filename);
printf("%d\n",strlen(ptr->filename));
ptr->filename[strlen(ptr->filename)] = '\0';
if (access(ptr->filename, F_OK) != -1) {
printf("exist\n");
return false;
} else {
//printf("does not exist\n");
return true;
}
}
I call this function by
while (Searchfile(&oldPacket)){
printf("Please input the file name in the format: ftp <file name> \n");
}
However the program is no longer working and it shows seg fault at
int filesize;
fp = fopen(oldPacket.filename, "rb");
fseek(fp, 0L, SEEK_END);//here is the seg fault
Anyone have some idea why this happen ?
I already printf each char of the filename and it looks correct....
Thanks in advance
You let ptr->filename point to an address of local variable userinput, and accessing this value once userinput has gone out of scope is undefined behaviour.
The reason for the segfault is probably that the value of filename, when accessed outside of Searchfile, may be garbage, such that the file will not be opened. The subsequent fseek will then be called with a NULL-value for fp...
A simple solution to overcome this would be to write static char userinput[100];, at least when you are not working in a multithreaded environment. Otherwise you'd have to reserve memory for ptr->filename and copy contents of userinput.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
printf("Transactional Shell Command Test.\n");
while(1) {
printf("Queue:");
char input[500];
fgets (input, 500, stdin);
if(strstr(input, "qb-write")){
printf("These are the commands you have queued:\n");
FILE *cmd = popen("cat /home/$USER/.queueBASH_transactions", "r");
char buf[256];
while (fgets(buf, sizeof(buf), cmd) != 0) {
printf("%s\n",buf);
}
pclose(cmd);
}
system(strncat("echo ",strncat(input," >> /home/$USER/.qb_transactions",500),500));
usleep(20000);
}
return 0;
}
I am attempting to make a concept for a transactional shell, and I'm having it output every command you enter into a file in the user's home directory. It's not completely finished, but I'm doing one part at a time. When I put in any input to the "shell", it crashes. Codeblocks tells me "Process returned -1 (0xFFFFFFFF)" and then the usual info about runtime. What am I doing wrong here?
strncat appends to its first argument in place, so you need to pass it a writable buffer as the first argument. You're passing a string literal ("echo "), which depending on your compiler and runtime environment may either overwrite unpredictable parts of the memory, or crash because it's trying to write to read-only memory.
char command[500];
strcpy(command, "echo ");
strncat(command, input, sizeof(command)-1-strlen(command));
strncat(command, " >> /home/$USER/.qb_transactions", sizeof(command)-1-strlen(command));
system(command);
As with the rest of your code, I've omitted error checking, so the command will be truncated if it doesn't fit the buffer. Also note that repeated calls to strncat are inefficient since they involve traversing the string many times to determine its end; it would be more efficient to use the return value and keep track of the remaining buffer size, but I'm leaving this as a follow-up exercise.
Of course invoking a shell to append to a file is a bad idea in the first place. If the input contains shell special characters, they'll be evaluated. You should open the log file and write to it directly.
char log_file[PATH_MAX];
strcpy(log_file, getenv("HOME"));
strncat(log_file, "/.qb_transactions", PATH_MAX-1-strlen(log_file));
FILE *log_file = fopen(log_file, "a");
…
while (1) {
…
fputs(cmd, log_file);
}
fclose(log_file);
(Once again, error checking omitted.)
This error is driving me nuts. Please help. The code compiles in gcc in terminal and in codeblocks IDE. I'm using Linux and C. It compiles and runs but theres no output in the second text file "onlydata.txt".
#include <stdlib.h>
#include <stdio.h>
/* Data Looks Like This...
E1 101223 9.2
E1 120231 8.4
E2 121212 400.2
I need this....
9.2
8.4
*/
struct Data
{
char *specimen;
int date;
double result;
};
int main()
{
char szBuffer[256];
unsigned int iCt=0;
Data* pData=NULL;
FILE* fpIn=NULL;
fpIn=fopen("data.txt","r"); //Open "Data.dat for read "r" access.
if(fpIn) //and loop through data to count lines.
{ //in iCt
while(!feof(fpIn))
{
fgets(szBuffer,256,fpIn);
iCt++;
}
fclose(fpIn);
}
printf("iCt = %d\n\n",iCt); //Allocate a buffer of Data type
pData=(Data*)malloc(iCt*sizeof(Data)); //to hold iCt objects
if(pData)
{
fpIn=fopen("Data.txt","r"); //Open "Data.dat for read "r" access.
if(fpIn) FILE *fp=NULL;
{
iCt=0;
while(!feof(fpIn)) //read data from text file into buffer
{
fscanf(fpIn,"%s%i%f",
&pData[iCt].specimen,
&pData[iCt].date,
&pData[iCt].result);
// printf("%10.2f\t%4.2f\t%f\t%f\t%f\t%u\t%4.2f\n",
// pData[iCt].specimen,
// pData[iCt].date,
// pData[iCt].result,
iCt++;
FILE *np=NULL;
np = fopen("onlydata.txt","w");
if(np)
fprintf (np," ", &pData[iCt].result);
fclose(np);
}
fclose(fpIn);
}
free(pData);
}
getchar();
return 0;
}
Linux filenames are case sensitive. The second fopen() will fail if the file is called "data.txt".
The actual problem you have stems from the following line:
fprintf (np," ", &pData[iCt].result);
It simply outputs a space to the file. I think you forgot a %f.
EDIT Missed the other obvious error noted by Didier Trosset. :)
you need to have specifier in your fprintf for the result, without the specifier it just writes a whitespace into the file
You should open you destination file only once, at the same time you open your source file.
Right now, for every line of the source file, you open the destination, truncate it, and write one line. In the end, you only got a single line (the last one) in your destination file.
Furthermore, your fprintf does only write a single space character: your format string should be "%f" or at least contain one %f. Actually, the parameter &pData[iCt].result is not used.
Note also that this parameter should not be passed by address, but by value: (remove the &).