The function is called as so,
printf("%d occurrences of %c in %s\n",
countoccurrences(argv[1], argv[1][0]),
argv[1][0], argv[1]);
and this is my function so far:
/* countcharinfile
* input: char *filename, char c
* output: the number of occurrences of char c inside file filename
*/
int countoccurrences(char *filename, char c)
{
// count the number of occurrences of c in the file named filename
FILE *fp = fopen(filename,"r");
int ch,count=0;
while ((ch = fgetc(fp) != EOF))
{
if (ch == c)
count++;
}
return count;
}
When I run the program, ./main Today is a beutiful day
I get the error Segmentation fault (core dumped)
It looks like you're using your function countoccurrences in main before it's been defined.
Add a function signature before main:
int countoccurrences(char *, char);
Or move the function itself to a place in your code before your main function.
Also:
you need to initialize your count variable to zero in countoccurences, and
you should check that fp != NULL before you use the file pointer. fopen will return NULL if it can't open the file.
When I run the program, ./main Today is a beutiful day
When you run your program this way, you are passing it 5 arguments, one for each word in your sentence. Review your function and your function call in main: the function wants a file name to search, which should be the first argument to your program, not the text to search. And the second argument should be the character to search for.
Since you're not checking the return value of fopen, your invocation here will cause problems, because you probably don't have a file named Today in the working directory.
C needs to know about your function signature before the call. Either:
Move your function before the call, or
Put a declaration before the call (at the global scope of course)
int countoccurrences(char *filename, char c);
You also need to initialize count (presumably to 0). You should make sure you are calling it with the right value. If you want to use the first character of the second parameter you should use argv[2][0].
The error indicates that the function declaration or definition was not visible at the point where it is called. Move the definition or put a declaration prior to main().
Other points:
Check return value of fopen()
Initialise count
buf is an unused local variable
For example:
FILE *fp = fopen(filename,"r");
if (fp)
{
int ch,count=0;
while ((ch = fgetc(fp)) != EOF)
{
if (ch == c) count++;
}
fclose(fp);
}
else
{
fprintf(stderr,
"Failed to open %s: %s\n",
filename,
strerror(errno));
}
Related
I have a very large program right now that I'm fairly certain that I should not publish publicly without getting into a lot of trouble so I'm going to try my best to explain the issue at hand.
I have 3 different functions, the names are different but the pointer names in the function match exactly, I'm not allowed to change the pointer names:
int function_1 (FILE \*in, FILE \* out, FILE \*changes);
int function_2(TYPEDEF STRUCT \*s, FILE \*in);
int function_3(TYPEDEF STRUCT \*s, FILE \*in);
My main function calls function_1 using function_1(stdin, stdout, changes) where changes is a pointer to a file stream that was opened in main.
In function1, I call function2(s,changes) and function_3(s,changes) in a loop. I also use fgetc(in) in function_1 after calling 2 and 3. I am failing in the first loop because I have a mismatch comparing characters between changes and stdin, when the are supposed to be the same.
For some strange reason, I find that by the time I get to the line int a=fgetc(in) in function_1, the stdin FILE stream has already lost two characters. If I add a line to fgetc(in) prior to calling function_2*,* I get the first letter in stdin and then my original int a=fgetc(in) shifts down one letter. Using this method, I determined that a character from stdin is lost after a call to function2 and another character from stdin is lost after function_3. However, I did not pass the *in pointer into those functions, I passed the *changes pointer.
I have never been more confused as to why this is happening, it doesn't make sense. If there was a problem with the fgetc(in) calls in the other two functions, it shouldn't only take off two characters as there are many of them in the other two functions, and those fgetc(in) calls are pulling the characters from the changes stream correctly.
Has anyone run into this before? Thanks in advance for any guidance.
edit:
I think this is as minimal of an example that I can get. I also just discovered that if I comment out the EOF If statement checks, I no longer lose the two characters.
#include <stdlib.h>
#include <stdio.h>
int next_struct(MYSTRUCT *s, FILE *in) {
int current_c = fgetc(in);
int eof_check= current_c;
if ((eof_check = getchar()) != EOF) {
//do stuff here
}
else {
return EOF;
}
//do more stuff
return 0;
}
int get_struct_c(MYSTRUCT *s, FILE *in) {
int c = fgetc(in);
int eof_check2= c;
if ((eof_check2=getchar()) != EOF) {
//do stuff
}
else {
return EOF;
}
return character;
}
int patch(FILE *in, FILE *out, FILE *diff) {
//intialize typedef struct
//create pointer to struct
while (!feof(diff)) {
if (next_struct(s,diff) == 0) {
//get charaters from diff and add to output
hunk_c = get_struct_c(s,diff);
read_c = fgetc(in);
fprintf(stderr, "%c\n", read_c);
}
return 0;
}
Description
I am trying to write a csv table, tablepath, and I need to include in it the name of the variables, which are in a text file, filepath. I am using a first function, read_par, to retrieve the names from filepath and a second function, store, to write in the table.
Problem
The table created is systematically missing the name of the first variable from the text file. The read_par function is functional and produces the expected output: a string containing the name of the variable, I also included it for context.
filepath
Here is the structure of the text file:
par1
0 1 0.5
par2
1 1 1
par3
0 1 1
par4
0 1 1
par5
0 1 1
par6
0 1 1
store
Here is the store function:
int store(int par_num, float sim_num, float **tab_param, char *filepath, char *tablepath){
int j;
char *name = NULL;
FILE* sim_table = NULL;
sim_table = fopen(tablepath, "w");
// Start the first line in the table
fprintf(sim_table,"simulation_number");
for(j=1; j < par_num+1; j++){
// If it is the last parameter -> create a new line
if(j == par_num){
name = read_name(j, filepath);
fprintf(sim_table,",%s\n", name);
}else{
/* If it is not the last parameter -> continue writing on
* the same line */
name = read_name(j, filepath);
fprintf(sim_table,",%s", name);
}
}
fclose(sim_table);
return 0;
}
read_name
Here is the read_name function:
char *strtok(char *line, char *eof);
char *read_name(int par_id, char *filepath){
char *par_name;
int count = 0;
FILE *file = fopen(filepath, "r");
if ( file != NULL ){
char line[256]; /* or other suitable maximum line size */
while (fgets(line, sizeof line, file) != NULL){ /* read a line */
if (count == (2*par_id)-2){
// strtok removes the \n character from the string line
strtok(line, "\n");
par_name = line;
fclose(file);
}
else{
count++;
}
}
}
else
{
printf("\n\n ERROR IN FUNCTION READ_PAR\n\nTEXT FILE IS EMPTY\n\n");
}
return par_name;
}
tablepath
The table I am obtaining looks like this:
┌─────────────────┬┬────┬────┬────┬────┬────┐
│simulation_number││par2│par3│par4│par5│par6│
└─────────────────┴┴────┴────┴────┴────┴────┘
With the par1 name missing, but all the other variable name successfully printed. I do not know where is the problem. Is it a problem in the for loop conditions or something to do with the par1 string itself?
Thanks for any help on this.
The problem is that read_name returns the address of a local variable (line). That local variable goes out of scope (and technically ceases to exist) when the function returns. So using the returned pointer results in undefined behavior.
Too see the problem more clearly, here's a simplified version of read_name with only the relevant lines shown:
char *read_name(int par_id, char *filepath){
char *par_name;
char line[256]; // line is a local variable
while (fgets(line, sizeof line, file) != NULL){
par_name = line; // par_name now points to the local variable
}
}
return par_name; // returning the address of the local variable
}
It was noted in the comments under the question that read_name was tested and was found to be functional. So how can it be wrong? That's the worst thing about undefined behavior in C. Sometimes the code appears to work during testing even though it is technically incorrect. And by technically incorrect, I mean that it will break at some point. For example, in the store function, if you add another function call between the call to read_name and the call to fprintf, there's a good chance that name will be corrupted, and won't print properly.
An easy solution in this case is to declare line with the static keyword:
static char line[256];
That way, line has static storage duration, which means it will continue to exist after read_name returns.
As stated in the title, i ask for the user to provide the filename and i use gets to save it in str. Then i try to access the file using the name and the program crashes.
int openFile(FILE *fp){
puts("What's the name of the file (and format) to be accessed?");
char str[64];
gets(str);
fp = fopen((const char *)str, 'r');
...
return 0;
In main:
FILE *fp; // file pointer
openFile(fp);
The filename i enter (data.txt) is indeed in the same directory as the rest of the project so that should not be the problem. I've tried testing if the file is opened correctly (which it should) but it keeps crashing right after i give the name.
The main problem is that you are trying to set an argument passed by value in a function and expect the value to be changed outside. This can't work.
Currently you have:
void openFile(FILE* fp) {
fp = ...
}
int main()
{
FILE* fp;
openFile(fp);
}
But fp in main() is passed as a pointer by value. Which means that inside openFile you are setting a local variable, while the passed one is not modified.
To solve the problem you can:
directly return a FILE* from openFile
accept a pointer to pointer argument to be able to set it, eg void openFile(FILE** fp) and then openFile(&fp)
Mind that the second argument of fopen is a const char* not a single char, "r" should be used.
It should be fp = fopen(str, "r");, because fopen() expects mode as a char * pointing to a string, rather than a single char.
Also, since parameters in C are passed by value, your fp won't get modified after openFile() is called. To get it work, you'll have to rewrite it, and call it by openFile(&fp);. Here is an example:
void openFile(FILE **fp) {
puts("What's the name of the file (and format) to be accessed?");
char str[64];
fgets(str, 64, stdin);
str[strcspn(str, "\n")] = '\0';
*fp = fopen(str, "r");
}
fgets() is used to provide buffer overflow protection.
This is code to write contents in file.
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
FILE *fp;
char ch(90);
fp = fopen("books.txt","w");
if(fp == NULL)
{
puts("Cannot open file");
}
printf("Enter lines of text:");
while(strlen(gets(ch)) > 0)
{
fputs(ch, fp);
}
fclose(fp);
}
I'm getting 4 errors. These are:
Cannot convert int to char * in function main().
Type mismatch in parameter __s in call to gets(char *) in function main().
Cannot convert int to const char * in function main().
Type mismatch in parameter __s in call to fputs(const char *,FILE *) in function main().
your definition of the char array is wrong I believe:
char ch(90);
must be
char ch[90];
In your code
char ch(90);
is considered as a function declaration, which is not what you want. you need to use the [] operator to denote an array, like
char ch[90]; //array named ch having 90 chars
After that, in case if(fp == NULL) is success (i.e., file opening is failed), just printing out a message is not sufficient. You should not use the returned fp further anywhere in the program, i.e., you have to skip all the statements involving that fp. Otherwise, using invalid file pointer will result in undefined behaviour.
That said,
never use gets(), use fgets() instead.
the proper signature of main() is int main(void).
Firstly:
Your character array definition should be:
char ch[90];
Secondly:
Your definition of the main should be:
int main(void)
Thirdly:
Consider using fgets() instead of gets().
Check the char array definition,
it should be like char ch[90];
I have a function that reads an input file and is supposed to modify the contents of a char** and a int*. The function is as follows:
void
input_parser(arguments* args, char** input, int* files) {
char buffer[MAX];
FILE *fr;
fr = fopen(args->file,"r");
if (fr == NULL) {
printf("No correct input file was entered\n");
exit(0);
}
while(fgets(buffer,MAX,fr) != NULL) {
input[*files] = strtok(buffer,"\n");
(*files)++;
}
fclose(fr);
return;
}
I have defined input and files as follows in the main program:
char* input[25];
files = 0;
I call the function as follows:
input_parser(args, input, &files);
The input file contains 3 lines as follows:
output1.xml
output2.xml
output3.xml
I notice that during the while loop the 'current' value is read correctly but stored in all input[*] resulting in:
input[0] = output3.xml
input[1] = output3.xml
input[2] = output3.xml
I would greatly appreciate if someone has any idea what is going wrong here.
The function is storing the address of the local variable buffer to each element in the input array: you need to copy the value returned by strtok(). The code as it stands is undefined behaviour as the buffer is out of scope once input_parser() returns, even it was not the logic is incorrect anyway.
If you have strdup(), you just use it:
input[*files] = strdup(strtok(buffer,"\n")); /* NULL check omitted. */
otherwise malloc() and strcpy(). Remember to free() the elements of input when no longer required.
Initialise input to be able determine which elements point to valid strings:
char* input[25] = { NULL };
You are going to end up having danging pointers, which are pointing inside your buffer after the buffer has been deallocated.