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];
Related
I have written a program employing the following concept:
I create an integer x pass by address to a function, along with a filename, said function opens file if available, scans the first line and sets the value that pX points to equal to the scanned line.
Only it's not working, and I don't see what I'm doing wrong. As far as I can tell the code below is generally how one would accomplish it, but I'm not sure if I'm not using scanf() correctly with the pointer or what.
void foo() {
char input[20] = "test.txt";
int x = 1;
bar(input, &x);
}
void bar(char *fileName, int *pX) {
FILE *fp = fopen(fileName, "r");
char *buffer = malloc(15 * sizeof(int));
fgets(buffer, 15, fp);
scanf(buffer, "%d", *pX);
free(buffer);
fclose(fp);
}
Change line :
scanf(buffer, "%d", *pX);
to :
sscanf(buffer, "%d", pX);
You need function sscanf for what you are trying to do.
Both scanf and sscanf take a pointer as an argument. pX is of type int *, therefore a pointer to an int and should work for you. What you pass, *pX, is the contents of this pointer, in other words an int.
Also, change line :
char *buffer = malloc(15 * sizeof(int));
to :
char *buffer = malloc(15 * sizeof(char));
or simply :
char *buffer = malloc(15);
and always check the result of malloc :
if (buffer == NULL){
...
}
First of all, there's no pass-by-reference in C, function parameters are all passed by value. By passing a pointer-to-data, we make the simulation of the achieving the same effect as pass-by-reference, but that does not mean C has any pass-by-reference concept.
That said, the problem seems to be
scanf(buffer, "%d", *pX);
^^^^
where
the current syntax is invalid and invokes undefined behavior. Probably you need sscanf().
px is already a pointer to int. Passing px will be correct and suffice.
Moral of the story: enable compiler warnings and pay heed to them. They are there for a reason. With proper warnings enabled, you should see something like
warning: format %d expects argument of type int *, but argument 3 has type int [-Wformat=]
Finally,
Always check the return value of fopen() for success before using the file pointer.
Check for the return value of scanf() to ensure successful scanning.
Check for the return value of fgets() to ensure success
...basically, check return value of all library calls to make sure they worked as expected.
You use scanf() incorrectly: either use scanf directly to parse standard input or use sscanf() to parse the string read by fgets(). Furthermore, pX is already a pointer to int, which is what sscanf() expects to store the int value it converts, pass it directly: sscanf(buffer, "%d", pX);
Here is a modified version:
int bar(const char *fileName, int *pX) {
char buffer[15];
FILE *fp = fopen(fileName, "r");
int success = 0;
if (fp != NULL) {
fgets(buffer, sizeof buffer, fp);
if (sscanf(buffer, "%d", pX) == 1)
success = 1;
fclose(fp);
}
return success;
}
void foo(void) {
int x = 1;
bar("test.txt", &x);
/* do something with x */
}
Notes:
allocating buf is unnecessary, just make it a local array with automatic storage.
char *buffer = malloc(15 * sizeof(int)); is incorrect: you allocate space for 15 int instead of 15 characters, which have a size of 1 by definition. Use the size of the destination type to avoid any inconsistencies:
char *buffer = malloc(15 * sizeof(*buffer));
always check the return value of malloc() to avoid potential undefined behavior.
reading from fp without checking if fopen succeeded has potential undefined behavior.
the contents of the array pointed to by filename is not modified, make it a const char *.
it may be useful for bar to return a success indicator.
enable more warnings at compile time: gcc -Wall -Wextra -Werror or clang -Weverything -Werror might have caught the mistakes in scanf.
I need to read a filename from a text file.
Then I have to use it as an argument for fopen .
Consequently , I need to read it as a const char* because this is the type fopen accepts as a first argument. How do I do this?
I tried something like:
FILE *a;
a=fopen("a.txt","r");
const char *filename
fgets(filename,100,a);
image=fopen(filename,"rb");
Something is be wrong as I receive a segmentation fault when I do this. I think that the variable filename is not well-received by the fopen function.
You may have seen that fopen() takes an argument of type (const char *), but you need to be able to modify your string before you pass it to the function. Also, you need to allocate space for your string, and you might consider allocating space for more than 100 chars. The stdio.h header file contains the macro FILENAME_MAX, which expands to an integer constant of the correct size for an array that will hold the longest possible file name string on a system. For example, you can use char filename[FILENAME_MAX];. When the identifier filename is encountered in the call to fopen(), it decays to a pointer to char, which is converted to a pointer to const char, as per the function prototype.
Furthermore, fgets() keeps the newline when if fetches a line of text, so you will need to remove that. You should check the result of fgets(), as it returns a NULL pointer in the event of an error or if it is called at end-of-file; otherwise it returns a pointer to the first char in filename[].
FILE *a;
a=fopen("a.txt","r");
char filename[FILENAME_MAX];
char *ch;
ch = fgets(filename,FILENAME_MAX,a);
/* Remove trailing newline */
if (ch) {
while (*ch != '\0' && *ch != '\n') {
++ch;
}
if (*ch == '\n') { // replace '\n' with '\0'
*ch = '\0';
}
image=fopen(filename,"rb");
}
First, your seg fault likely comes from trying to use memory that you do not own. i.e. by creating the variable:
const char *filename;
And not giving it any memory ([c][m]alloc) before trying to use it.
Regarding your statement:
Consequently , i need to read it as a const char*.
Not necessarily.
The first argument of the fopen prototype: "FILE *fopen(const char *filename, const char *mode)" simply guarantees that the argument passed in that position will be treated as a const char * within the fopen function.
The argument can be passed using a simple char *, eg. either of these forms:
char *filename = {"somefilename.txt"};
or
char filename[80];
strcpy(filename, "somefilename.txt");
And, as mentioned in comments, and other answers, remove the newline character, \n before passing as an argument.
I am trying to write a program that reads data from a file and puts it into a struct array. I have succeeded in putting it into the array but I then get a segmentation fault. I believe I have to use malloc to initialize the struct array but I am new to programming and don't really understand how to do this. Thanks for your help! I have copied pieces of my code so you can see what I've done. I have not included my functions in this code.
struct Weather
{
char location;
int daynum;
double temp;
double precip;
};
int main (void)
{
FILE*openFile;
char buffer[COLS][ROWS];
int i = 0;
struct Weather loc1; //initialize here?
for (i = 0; i <200; i++)
{
fgets (buffer[i], ROWS, openFile);
parseLine(buffer[i], &loc1);
printf ("%d %c %d %.2lf %.2lf\n",i, loc1.location, loc1.daynum, loc1.temp, loc1.precip);
}
}
Your file stream (openFile) is not initialized; it does not actually point to a file. As yano said in his comment, use fopen() in order to properly initialize the file pointer.
You must initialize the file stream with fopen() before any I/O operations!
int main()
{
char filename[64];
FILE *fp;
snprintf(filename, sizeof(filename), "hello1234.txt");
if(NULL == (fp = fopen(filename, "r")))
{
printf("err, failed when fopen(), %s %s[%d].\n", __FILE__, __FUNCTION__, __LINE__);
return -1;
}
//your code here
return 0;
}
Initialize the struct
Note that malloc() cannot initialize the struct.
two methods:
M0:
struct Weather loc1;
memset(&loc1, 0, sizeof(struct Weather));
M1:
struct Weather loc1 = {0};
man malloc or click the link for a malloc manual.
Multiple problems in your code:
The stream pointer openFile is uninitialized, calling fgets() for it invokes undefined behavior. You want to open a file for fopen() or set the value of openFile to the standard input stream stdin.
The 2D char array should be defined in the other order:
char buffer[ROWS][COLS];
you should use the same constant for the loop counter and the 2D array definition: ROWS might be defined to something less than 200.
the size of the line buffer is COLS, pass that to fgets().
you should test the return value of fgets(): it returns NULL at end of file and the contents of the destination array is indeterminate in this case.
whether or not to initialize loc1 depends on what the parseLine() function does. It would make sense that parseLine() make no assumptions about the contents of the destination structure, but the source has not been posted, so we cannot know for sure.
the printf format specifier for type double is %f, the extra l is simply ignored.
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.
I need to read some data from text file and store it in 2D-array.
This code works good:
#include <string.h>
#include <stdio.h>
int main() {
FILE *f = fopen("Read.txt", "r");
char buff[100][100];
char str[100];
int i = 0;
while(fgets(str, 100, f)) {
strcpy(buff[i], str);
i++;
}
return 0;
}
But why doesn't it work when I try to change buff definition in line 5 to:
char (*buff)[100];
I expected this definition to work too.
The error I get:
Run-Time Check Failure #3 - The variable 'buff' is being used without being defined
char (*buff)[100];
Here buff is a pointer to an array of 100 characters. So first you should make the pointer point to valid memory location before storing some value in it.
Presuming you want to go for dynamic memory allocation then you can have
char *buff[100];
Now in the fgets() loop allocate memory to each pointer individually like
buff[i] = malloc(100);
Note here buff is an array of 100 char pointers.