I have successfully created a quiz program that first askes the user to input their name.
After the quiz is over, the score is first printed to screen and then would be printed into a username.txt file.
Meaning, the actual users name like John.txt or Amy.txt or bob.txt.
Right now, I have predefined
report_file = fopen ("username.txt","w");
This works 100% yet naturally I have failed to properly identify the files each time the quiz is run for different people and recorded into the file.
I've seen suggestions for sprintf, snprintf, ofstream, istream, and the like.
All are new concepts to me and have no clue how to move forward...any help would be greatly appreciated.
If anyone wants or cares to see my program it is quiet nice and I'd be happy to share but do not intend to burden anyone to read my entire program during this ask for help. :)
Your are not using "username.txt" for all users I hope. And what do you do with the name a user enters when he start the quiz?
You might need something like that in your code, see the docs for sprintf
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char** argv)
{
FILE* pf = NULL;
char username[250];
char userfile[255];
printf("username: ");
scanf("%s", username);
sprintf(userfile, "%s.txt", username);
pf = fopen(userfile, "w");
fprintf(pf, "%d", 100);
fclose(pf);
return 0;
}
You might also want to have a look at fopen to see what flags for opening you will need for your requirements
If you have their username, just save it into a char array, and then call open with O_CREAT set. This will create the file if its not created, and since you have their username, it will create a file with their username.
I've seen suggestions for sprintf, snprintf, ofstream, istream, and the like.
So why dont use them?
char buffer [256];
sprintf(buffer, "%s.txt", username);
report_file = fopen (buffer,"w");
username is obviously an zero terminated string which contains the name of the user
EDIT: For further information you can visit http://www.cplusplus.com/reference/cstdio/sprintf/
To create the file name from a user name, you could use snprintf():
#include <stdio.h>
#include <stdlib.h>
/* ... */
const char* filename_format = "%s.txt";
int n = -1;
char* filename = NULL;
if ((n = snprintf(NULL, 0, filename_format, username)) < 0 ||
(filename = malloc(n+1)) == NULL ||
snprintf(filename, n+1, filename_format, username) != n) {
free(filename);
return error;
}
/* use filename here... */
free(filename); /* clean up */
where username is a '\0'-terminated C string e.g., you could get it using readline():
#include <readline/readline.h> /* readline or editline, etc libraries */
/* ... */
char* username = NULL;
if ((username = readline("Enter your name: ")) == NULL) return error;
/* use username here... */
free(username); /* clean up */
To compile and link:
$ gcc -std=c99 your_source.c -o program-name -lreadline
Related
Today I decided to learn to code for the first time in my life. I decided to learn C. I have created a small program that checks a txt file for a specific value. If it finds that value then it will tell you that that specific value has been found.
What I would like to do is that I can put multiple files go through this program. I want this program to be able to scan all files in a folder for a specific string and display what files contain that string (basically a file index)
I just started today and I'm 15 years old so I don't know if my assumptions are correct on how this can be done and I'm sorry if it may sound stupid but I have been thinking of maybe creating a thread for every directory I put into this program and each thread individually runs that code on the single file and then it displays all the directories in which the string can be found.
I have been looking into threading but I don't quite understand it. Here's the working code for one file at a time. Does anyone know how to make this work as I want it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
//searches for this string in a txt file
char searchforthis[200];
//file name to display at output
char ch, file_name[200];
FILE *fp;
//Asks for full directory of txt file (example: C:\users\...) and reads that file.
//fp is content of file
printf("Enter name of a file you wish to check:\n");
gets(file_name);
fp = fopen(file_name, "r"); // read mode
//If there's no data inside the file it displays following error message
if (fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
//asks for string (what has to be searched)
printf("Enter what you want to search: \n");
scanf("%s", searchforthis);
char* p;
// Find first occurrence of searchforthis in fp
p = strstr(searchforthis, fp);
// Prints the result
if (p) {
printf("This Value was found in following file:\n%s", file_name);
} else
printf("This Value has not been found.\n");
fclose(fp);
return 0;
}
This line,
p = strstr(searchforthis, fp);
is wrong. strstr() is defined as, char *strstr(const char *haystack, const char *needle), no file pointers in it.
Forget about gets(), its prone to overflow, reference, Why is the gets function so dangerous that it should not be used?.
Your scanf("%s",...) is equally dangerous to using gets() as you don't limit the character to be read. Instead, you could re-format it as,
scanf("%199s", searchforthis); /* 199 characters + \0 to mark the end of the string */
Also check the return value of scanf() , in case an input error occurs, final code should look like this,
if (scanf("%199s", searchforthis) != 1)
{
exit(EXIT_FAILURE);
}
It is even better, if you use fgets() for this, though keep in mind that fgets() will also save the newline character in the buffer, you are going to have to strip it manually.
To actually perform checks on the file, you have to read the file line by line, by using a function like, fgets() or fscanf(), or POSIX getline() and then use strstr() on each line to determine if you have a match or not, something like this should work,
char *p;
char buff[500];
int flag = 0, lines = 1;
while (fgets(buff, sizeof(buff), fp) != NULL)
{
size_t len = strlen(buff); /* get the length of the string */
if (len > 0 && buff[len - 1] == '\n') /* check if the last character is the newline character */
{
buff[len - 1] = '\0'; /* place \0 in the place of \n */
}
p = strstr(buff, searchforthis);
if (p != NULL)
{
/* match - set flag to 1 */
flag = 1;
break;
}
}
if (flag == 0)
{
printf("This Value has not been found.\n");
}
else
{
printf("This Value was found in following file:\n%s", file_name);
}
flag is used to determine whether or not searchforthis exists in the file.
Side note, if the line contains more than 499 characters, you will need a larger buffer, or a different function, consider getline() for that case, or even a custom one reading character by character.
If you want to do this for multiple files, you have to place the whole process in a loop. For example,
for (int i = 0; i < 5; i++) /* this will execute 5 times */
{
printf("Enter name of a file you wish to check:\n");
...
}
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.
I'm a complete noob to C and I wondered why if I take a user input why it wont find the file but when I hard code it using:
const char * fn = "/Users/james/Documents/test.rtf";
It seems to work fine?
char text[100];
fputs("File location: ", stdout);
fflush(stdout);
fgets(text, sizeof text, stdin);
FILE *fp = fopen(text,"r");
if( fp ) {
printf("\nFile Exists");
fclose(fp);
} else {
printf("\nFiles doesn't exist");
}
Any help would be awesome, or just a point to some online source that I have clearly not been able to find.
:)
fgets reads a line and keeps the final newline character. You'll have to strip that off by
text[strlen(text) - 1] = '\0';
(After doing the proper error checking, of course.)
You can use access() to check whether file exists or not
For access you need to provide path of the file and mode.
Prototype of access is
int access(const char *pathname, int mode);
access() returns zero if file exists.
For more information visit: http://linux.die.net/man/2/access
My goal is to gather input and open files based on that input.
FILE*
open_input_file (char* fileName) //opens source file to be read
{
return fopen(fileName, "r");
}
In an earlier function, I collect input from the user and save it to fileName. When I debug the program, it tells me fopen is returning NULL. That's not what I want, and I'm not sure where the problem is.
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName); // infileName is an output parameter for this
inFile = open_input_file(infileName);
}
I don't know what the problem is. Any thoughts?
If fopen returns NULL, the open failed. errno will hold the failure code and strerror(errno) will return a short description of why the open failed.
#include <errno.h>
#include <string.h>
...
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName); // infileName is an output parameter for this
if (!(inFile = open_input_file(infileName))) {
fprintf(stderr, "Error opening '%s': %s\n",
infileName, strerror(errno));
} else {
// open successful
...
}
}
Off-topic
gather_input better make sure infileName is null-terminated to prevent buffer overflows. The simplest way to do this is to define the size of the file name buffer as a macro and set the last character to 0.
#define FILENAMELEN 32
void gather_input(char infileName[]) {
...
infileName[FILENAMELEN-1]=0;
}
int main(void)
{ FILE* inFile = NULL;
char infileName[FILENAMELEN] = {'\0'};
This isn't very flexible. You could instead pass the size of the file name buffer into gather_input.
#define LENGTH(a) (sizeof(a) / sizeof(a[0]))
void gather_input(char infileName[], size_t len) {
...
infileName[len-1]=0;
}
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName, LENGTH(infileName)); // infileName is an output parameter for this
An alternative to setting the last character, if using standard string manipulation functions, is to use the strl* functions (strlcpy and strlcat) rather than their unbounded cousins. If you aren't using strl*, you should be using strncpy and strncat.
Have you checked that the file pointed to by inFilename exists on your HDD ?
Check the value of infileName in your debugger or put a printf statement to show the value on screen. printf("'%s'\n", infileName);
Did you call fclose() on your file inside the open_input_file() call. Maybe the file is still locked ?
Edit: I just checked the code. I have modified your english_to_morse() function. 1. The while statement is easier to follow than the for. 2. fgetc() returns an int and not a char.
At the top of the initialise I added this. This initialises every string in the array with and undefined string of ".??.". This will make it easier to find strange bugs as everything in your array is at least initialised.
I have modified different sections of the code but you should be able to follow.
initialize_morse_alphanum (char morseStrings[91][6])
{
for (int i=0;i<91;i++)
strcpy(morseStrings[i], ".??.");
....
....
void
english_to_morse(FILE* inputFile, FILE* outputFile, char morseStrings[91][6])
{ int convert;
convert = fgetc(inputFile);
while (convert != EOF)
{
fputs(morseStrings[convert], outputFile);
fputc(' ', outputFile);
printf ("%s ", morseStrings[convert]);
convert = fgetc(inputFile);
}
}
open_output_file (char* fileName) //opens destination file to be written
{ FILE* handle = NULL;
handle = fopen (fileName, "w"); <---- Remove the * from filename
return handle; }
Also, as mentioned in a different answer, it would be good to add some bounds checks to different areas of the code. At the moment it is quite prone to crashing. If my input file contains a lowercase 'a' (ascii 96) your program will be accessing memory that is out of bounds. So you should add a line like if (convert >= '0' && convert <= 'Z') in there somewhere. I will let you work that out.
Make sure that gather_input works properly. Could it be a problem because you're trying to read a file you're also writing on? In this case, try to close and open again the stream.
I've been trying to get this code to work for hours! All I need to do is open a file to see if it is real and readable. I'm new to C so I'm sure there is something stupid I'm missing. Here is the code (shorthand, but copied):
#include <stdio.h>
main() {
char fpath[200];
char file = "/test/file.this";
sprintf(fpath,"~cs4352/projects/proj0%s",file);
FILE *fp = fopen(fpath,"r");
if(fp==NULL) {
printf("There is no file on the server");
exit(1);
}
fclose(fp);
//do more stuff
}
I have also verified that the path is correctly specifying a real file that I have read permissions to. Any other ideas?
Edit 1: I do know that the fpath ends up as "~cs4352/projects/proj0/test/file.this"
Edit 2: I have also tried the using the absolute file path. In both cases, I can verify that the paths are properly built via ls.
Edit 3: There errno is 2... I'm currently trying to track what that means in google.
Edit 4: Ok, errno of 2 is "There is no such file or directory". I am getting this when the reference path in fopen is "/home/courses1/cs4352/projects/proj0/index.html" which I verified does exist and I have read rights to it. As for the C code listed below, there may be a few semantic/newbie errors in it, but gcc does not give me any compile time warnings, and the code works exactly as it should except that it says that it keeps spitting errno of 2. In other words, I know that all the strings/char array are working properly, but the only thing that could be an issue is the fopen() call.
Solution: Ok, the access() procedure is what helped me the most (and what i am still using as it is less code, not to mention the more elegant way of doing it). The problem actually came from something that I didn't explain to you all (because I didn't see it until I used access()). To derrive the file, I was splitting strings using strtok() and was only splitting on " \n", but because this is a UNIX system, I needed to add "\r" to it as well. Once I fixed that, everything fell into place, and I'm sure that the fopen() function would work as well, but I have not tested it.
Thank you all for your helpful suggestions, and especially to Paul Beckingham for finding this wonderful solution.
Cheers!
The "~" is expanded by the shell, and is not expanded by fopen.
To test the existence and readability of a file, consider using the POSIX.1 "access" function:
#include <unistd.h>
if (access ("/path/to/file", F_OK | R_OK) == 0)
{
// file exists and is readable
}
First, file needs to be declared as char* or const char*, not simply char as you've written. But this might just be a typo, the compiler should at least give a warning there.
Secondly, use an absolute path (or a path relative to the current directory), not shell syntax with ~. The substitution of ~cs4352 by the respective home directory is usually done by the shell, but you are directly opening the file. So you are trying to open a file in a ~cs4352 subdirectory of your current working directory, which I guess is not what you want.
Other people have probably produced the equivalent (every modern shell, for example), but here's some code that will expand a filename with ~ or ~user notation.
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif
#include <assert.h>
#include <limits.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char *relfname(const char *name, char *buffer, size_t bufsiz)
{
assert(name != 0 && buffer != 0 && bufsiz != 0);
if (name[0] != '~')
strncpy(buffer, name, bufsiz);
else
{
const char *copy;
struct passwd *usr = 0;
if (name[1] == '/' || name[1] == '\0')
{
usr = getpwuid(getuid());
copy = &name[1];
}
else
{
char username[PATH_MAX];
copy = strchr(name, '/');
if (copy == 0)
copy = name + strlen(name);
strncpy(username, &name[1], copy - &name[1]);
username[copy - &name[1]] = '\0';
usr = getpwnam(username);
}
if (usr == 0)
return(0);
snprintf(buffer, bufsiz, "%s%s", usr->pw_dir, copy);
}
buffer[bufsiz-1] = '\0';
return buffer;
}
#ifdef TEST
static struct { const char *name; int result; } files[] =
{
{ "/etc/passwd", 1 },
{ "~/.profile", 1 },
{ "~root/.profile", 1 },
{ "~nonexistent/.profile", 0 },
};
#define DIM(x) (sizeof(x)/sizeof(*(x)))
int main(void)
{
int i;
int fail = 0;
for (i = 0; i < DIM(files); i++)
{
char buffer[PATH_MAX];
char *name = relfname(files[i].name, buffer, sizeof(buffer));
if (name == 0 && files[i].result != 0)
{
fail++;
printf("!! FAIL !! %s\n", files[i].name);
}
else if (name != 0 && files[i].result == 0)
{
fail++;
printf("!! FAIL !! %s --> %s (unexpectedly)\n", files[i].name, name);
}
else if (name == 0)
printf("** PASS ** %s (no match)\n", files[i].name);
else
printf("** PASS ** %s -> %s\n", files[i].name, name);
}
return((fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
}
#endif
You could try examining errno for more information on why you're not getting a valid FILE*.
BTW-- in unix the global value errno is set by some library and system calls when they need to return more information than just "it didn't work". It is only guaranteed to be good immediately after the relevant call.
char file = "/test/file.this";
You probably want
char *file = "/test/file.this";
Are you sure you do not mean
~/cs4352/projects/proj0%s"
for your home directory?
To sum up:
Use char *file=/test/file.this";
Don't expect fopen() to do shell substitution on ~ because it won't. Use the full path or use a relative path and make sure the current directory is approrpriate.
error 2 means the file wasn't found. It wasn't found because of item #2 on this list.
For extra credit, using sprintf() like this to write into a buffer that's allocated on the stack is a dangerous habit. Look up and use snprintf(), at the very least.
As someone else here mentioned, using access() would be a better way to do what you're attempting here.