So, I have some code that reads a file line by line.
Here is that code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct alumnus {
int *yearGraduated;
char firstName[30];
char lastName[30];
} Alumns;
void printer ( Alumns *a ) {
printf("Year: %*d", a->yearGraduated);
printf(" First Name: %s", a->firstName);
printf(" Last Name: %s", a->lastName);
}
int main(int argc, const char * argv[])
{
Alumns a;
char *home = getenv("HOME");
char path[100] = "/Desktop/Alumni.txt";
strcat(home, path);
FILE *fp;
fp = fopen(home, "r");
while ( fp ) {
fscanf(fp, "%d,%s,%s", a.yearGraduated, a.firstName, a.lastName);
printer(&a);
}
return 0;
}
I am getting an error # line 2 in the printer function
printf("Year: %d", a->yearGraduated);
My IDE says the following about this line:
Format Specifies type 'int' but the argument has type 'int *'
Another error only appears when I compile the code. Error is at line:
a.yearGraduated, a.firstName, a.lastName);
My IDE says this about it:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
Yes, the file IS existent, and yes, it is formatted the right way.
Any ideas on how to debug this?
I was recommended to make the int inside the structure not a pointer, but I'm not sure.
yearGraduated is a pointer. You need to allocate space for it and dereference it in the printf statement.
So...
a.yearGraduated = malloc(sizeof(int));
fscanf(fp, "%d,%s,%s", a.yearGraduated, a.firstName, a.lastName);
free(a.yearGraduated);
and in the function
printf("Year: %d", *a->yearGraduated);
or you could make the int in the structure not a pointer and it will not be an issue.
Regarding the first error: all the information you need is in the error message. You provide a pointer to an int where printf expects an int. Unless you have a reason to make yearGraduated a pointer you should change it to an int:
typedef struct alumnus{
int yearGraduated;
...
} Alumns;
If you do this you need to change the first argument to fscanf to pass the address of a.yearGraduated: &a.yearGraduated.
If you choose to keep it a pointer you must allocate it:
Alumns a;
a.yearGraduated = malloc(sizeof a.yearGraduated);
Then in the printer you must dereference it to printf:
printf("Year: %*d", *a->yearGraduated);
The reason the code crashes at the fscanf is because the memory at a.yearGraduated was not allocated so fscanf tries to write to unallocated memory, which is a bad idea.
ADD: (in response to your comment)
The reason the program loops forever is because while(fp) will loop forever (unless fopen fails, in which case it won't loop at all). I'm assuming your reasoning is that fp will become false when the end of the stream is reached. But fp is just a (pointer-)value and fscanf won't (can't) change it. To stop the loop when the end of the stream is reached use feof
Related
I've defined a struct and a function that returns a pointer to that struct and whenever I try to invoke it I get a runtime error says ** error: conflicting types for ‘readVirus’**
typedef struct virus {
unsigned short SigSize;
char virusName[16];
unsigned char* sig;
}virus;
virus* readVirus(FILE* file){
virus *res;
res=(virus*)malloc(sizeof(virus));
fread(&res->SigSize,2,1,file);
fread(&res->virusName,16,1,file);
res->sig=(char*)malloc(res->SigSize);
fread(res->sig,res->SigSize,1,file);
return res;
free(res);
}
int main(int argc, char **argv) {
FILE *input;
input = fopen(argv[1],"rb");
virus *res;
res=(virus*)malloc(sizeof(virus));
res=readVirus(input);
printf("%s",res->virusName);
free(res);
fclose(input);
}
I've tried to copy the body of readVirus into main directly and deleted the function and it worked perfectly, so I don't think that its an function implementation issue.
thanks in advance :)
having
typedef struct virus {
unsigned short SigSize;
char virusName[16];
unsigned char* sig;}
struct virus* readVirus(FILE* file){
first a ';' is missing after the '}' of the struct and you do not define the type virus, so you need to use struct virus every where in your code
But probably you wanted wanted :
typedef struct virus {
unsigned short SigSize;
char virusName[16];
unsigned char* sig;
} virus;
to allow to just write virus without the struct after its definition
I encourage you to use an uppercase character to start the name of your types, so Virus rather than virus, that help the reading of the code making a distinction with the name of the variables for instance
Problems in main
I get a runtime error says ** error: conflicting types for ‘readVirus’**
This is a message produced when you compile your program, not when you execute it and this is because in that line :
res->sig=(char*)malloc(res->SigSize);
res is a pointer to a virus but your cast is (char*), the types are not the same.
You can fix the cast to use (virus*) but in fact you can just remove it.
Doing :
res=malloc(sizeof(virus));
res=readVirus(input);
the first assignment is lost, introducing a memory leak, remove the fiest assignment
Note in main you do not free res too, at the end of the program this is not a problem, except if you want to check the memory usage with a tool like valgrind
You use argv[1] without checking before the program received an argument, I encourage you do do something like that at the beginning of your program :
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", *argv);
return -1;
}
else {
I encourage you to check the result of fopen to check you was able to open the file and to signal when it is not the case. If you have the function strerror use it, for instance :
if (input == NULL) {
fprintf(stderr, "cannot open %s : ", argv[1], strerror(errno));
return -1;
}
Flush your printing with a final newline, and you just want to print a string, so in main replace
printf("%s",res->virusName);
by
puts(res->virusName);
Problems in readVirus
In
fread(&res->SigSize,2,1,file);
fread(&res->virusName,16,1,file);
do not use literal number for the size, use sizeof to get the right size whatever happens :
fread(&res->SigSize, sizeof(res->SigSize), 1, file);
fread(&res->virusName, sizeof(res->virusNamee), 1, file);
I also recommend you to check your reads success and to signal when there is an error
Are you sure the file is a binary file where sigSize is the binary representation ? I mean for the size 1234 the file contains the byte of code 4 then the byte of code 210 or the reverse
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.
I am working with the following text file: https://mega.nz/#!EN4iRJxA!VtKFEl9dlQHWHIzcgfOfpXTt9_ill_YkgsLWL3nORLg
And the following code:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int id;
char lastname[25];
char name[20];
float average;
}student;
int main(){
int i;
student *pointer= (student*) malloc(3);
FILE *file= fopen("Struct.txt", "r");
fread(pointer, sizeof(student), 3, file);
for(i= 0; i< 3; i++){
printf("Id: %d\nName: %s\nLast name: %s\nAverage: %.2f\n",
(pointer+ i) -> id,
(pointer+ i) -> name,
(pointer+ i) -> lastname,
(pointer+ i) -> average);
}
fclose(file);
system("pause");
return 0;
}
When I delete the fclose function it works but I checked it and seems to be correct. What am I missing?
It has nothing to do with your fclose, instead you need to fix two things:
You need to check the return error of fopen:
if( NULL == file )
{
printf( "Cannot open\n" );
exit( 1 );
}
Your malloc code doesn't look right, should be:
student *pointer= malloc(3 * sizeof(student));
Your program isn't allocating memory the way you think it is. malloc(3) returns three bytes of memory. Most likely the file pointer is immediately after it in memory
[ | | ][*FILE]
When you read in the file, the data first goes in to the three bytes of memory you've allocated. But since it doesn't fit, it keeps going and overwrites the memory containing the pointer to the file too.
[student data student data]
Then calling fclose closes the file at dat or whatever was read in from the file. This is a programming error, sometimes called a "wild pointer dereference", and if the data read in doesn't point to something that can be closed like a file can (as is happening to you) the program will crash.
The fixes suggested by artm should resolve your problem, but I thought this explanation might help you understand why you saw the crash.
I'm writing a C program which begins by opening and reading a file of 50 movie titles, each written on a single line. Next I am attempting to assign each line (or movie title) of the file into each element of an array called FilmArray[51]. I am using strcpy() to do so but the program crashes each time it reaches the first loop of the strcpy and I cannot seem to figure out where I've gone wrong...
int main()
{
int i=0;
char array[51];
char FilmArray[51];
bool answer;
FILE *films;
films = fopen("filmtitles.txt", "r");
if(films == NULL){
printf("\n ************* ERROR *************\n");
printf("\n \"filmtitles.txt\" cannot be opened.\n");
printf("\n PROGRAM TERMINATED\n");
exit(EXIT_FAILURE);
}
while(fgets(array, sizeof array, films) != NULL){
printf("%d. %s",i, array);
strcpy(FilmArray[i], array);
i++;
}
FilmArray is an array of characters, not an array of strings.
So when you're doing
strcpy(FilmArray[i], array);
the compiler will convert the value in FilmArray[i] to a pointer and use that as the destination of the string. This will lead to undefined behavior.
In fact, the compiler should be shouting a warning at you for this, and if it doesn't then you need to enable more warnings because warnings are messages about things that the compiler think are suspect and may lead to UB.
Your code is essentially trying to do an integer to pointer conversion passing char to parameter of type char *. Try using & with strcpy :
strcpy(&FilmArray[i], array);
& designates the use of a pointer for FilmArray[i]
suggest the following code
which compiles with no errors/warnings
is complete (given the posted code)
eliminates a lot of the code clutter
eliminates the 'magic' numbers buried in the code
#include<stdio.h>
#include<stdlib.h>
#define MAX_NUM_FILMS (51)
#define MAX_FILM_TITLE_LEN (51)
int main()
{
int i=0;
char FilmArray[ MAX_NUM_FILMS ][ MAX_FILM_TITLE_LEN ] = {{'\0'}};
FILE *films;
films = fopen("filmtitles.txt", "r");
if(films == NULL)
{
printf("\n ************* ERROR *************\n");
printf("\n \"filmtitles.txt\" cannot be opened.\n");
printf("\n PROGRAM TERMINATED\n");
exit(EXIT_FAILURE);
}
// implied else, fopen successful
while(fgets(&FilmArray[i][0], MAX_FILM_TITLE_LEN, films))
{
printf("%d. %s\n",i, FilmArray[i]);
i++;
}
// other code here
fclose( films ); // cleanup
return(0);
} // end function: main
when it comes to C i am not a noob - i'm more like a total & complete stupid ignorant noob! i am trying to write a program to parse simple text files, and i would like to make it as general as possible(why i use getline). well here is my code:
//afile.c
#include <stdio.h>
#include <stdlib.h>
main( )
{FILE *fp1;
char *filename;
char **line;
size_t *sz;
int s;
filename = "n";
if ((fp1 = fopen(filename,"r")) == NULL ){printf("error...");return 1;}
do {
s = getline(&line,sz,fp1);
if (s != -1)
printf(" %s \n",line);//<-- %s seems to be wrong! %*s removes the gcc warning
} while (s != EOF);
fclose(fp1);}
I am pretty sure its some pointer allocation problem, but i really cant figure out where it is. i've found out that replacing %s with %s makes the compiler warning disappear, but it results in an infinity of \t(tabs) being written in the terminal.
By the way, the error message i get is:
stack smashing detected *: ./afile terminated
Segmentation fault
getline expects an argument of type char**, and you supplied &line, which is char***. Additionally, getline acts on the current value of the value its first arguments points to (so, the value of line), and you didn't initialize it. Change your program to:
char *line = NULL;
and it should be fine.
You failed to initialize the line variable, and it contains a random value. Readline probably tries to realloc() it.
UPDATE: the definition for line is also wrong, only one asterix needed, as pointed out by others.
int main(void )
{
FILE *fp1;
char *filename;
char *line = NULL; /* <- here */
size_t *sz;
int s;
...
}
Your pointer redirections are inconsistent. The variable line is declared:
char **line;
Which is a pointer to a pointer to a character, or a pointer to a string. getline() expects a pointer to a string, but you pass &line - a pointer to a pointer to a string.
Finally, your printf() format specified is %s, do it wants to format a string, but you give it a pointer to a string.
Long story short: remove an asterisk to create
char *line;