Trouble with fgets() and strcpy() - c

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

Related

I am trying to store a list of strings from a file into an array in C

I am trying to read a file containing a list of words and store them in an array. After storing I randomly tried to print the 10th element to ensure that the code did what it's supposed to but I was unsuccessful.
I also get the following warning and I don't get what it's telling me:
warning: assignment to ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
22 | dict[i][j]=word_scanned;
#include <stdio.h>
#include <stdlib.h>
int main() {
char word_scanned[50];
char dict[102402][50];
int i,j;
FILE *fptr;
if ((fptr = fopen("/usr/share/dict/words", "r")) == NULL) {
printf("Error! opening file\n");
// Program exits if file pointer returns NULL.
exit(1);
}
for(i=0; !feof(fptr); i++){
fscanf(fptr,"%s", word_scanned);
for (j=0; j<50; j++){
dict[i][j]=word_scanned;
}
}
printf("%s\n",dict[9]);
fclose(fptr);
return 0;
}
dict[i][j]=word_scanned[j]; is the answer.
But also read about strncpy, and also FYI fscanf(fptr,"%s", word_scanned); is not safer than directly scanning into fscanf(fptr,"%s", dict[i]); because word_scanned is 50 bytes long, too. Any string longer than 50 characters will cause memory error, so this additional buffer does not help at all.

I think I declared and used arrays the wrong way

I'm trying to create a simple C program that reads lines of string from a file then output it to the terminal, but apparently it keeps crashing and I don't know where I went wrong...I suspect that it might be the way that I'm handling the arrays in my code, because I'm still very new to C, so I'm still getting used to the ways that arrays are used and declared..
This is what my code currently looks like:
typedef struct my_string
{
char str[256]; // my string contains an array of 255 characters + null
} my_string;
//Output lines from the file into terminal
void print(int count, my_string a[20]) {
for (int i = 0; i < count; i++)
{
printf("%s\n", a[i]);
}
}
//Read lines from file
void read(FILE *file_ptr) {
int i;
int numberOfLines;
my_string lineArray[20];
fscanf(file_ptr, "%d\n", &numberOfLines);
for (i=0; i < numberOfLines; i++) {
fscanf(file_ptr, "%[^\n]\n", lineArray[i].str);
}
print(numberOfLines, lineArray);
}
void main()
{
FILE *file_ptr;
// open the file and read from it
if ((file_ptr = fopen("mytestfile.dat", "r")) == NULL)
printf("File could not be opened");
else {
read(file_ptr);
}
fclose(file_ptr);
}
The text file that I'm trying to read from is this:
10
Fred
Eric
James
Jaiden
Mike
Jake
Jackson
Monica
Luke
Kai
Thanks
A few things.
1) The return type for main is int and not void.
int main(){
...
}
2) If you couldn't open the file, then it shouldn't be closed. Move the fclose into the else statement.
else{
read(file_ptr);
fclose(file_ptr);
}
3) In your print function, make sure that the string is being printed and not the struct address. The compiler should've given a warning.
void print(int count, my_string a[20]) {
for (int i = 0; i < count; i++)
{
printf("%s\n", a[i].str); /* a[i].str not a[i]*/
}
}
One of the posts has been accepted as an answer to this question but it doesn't give the specific reason for the problem that OP has asked:
...but apparently it keeps crashing and I don't know where I went wrong.....
Hence I am posting this answer.
In your print(), you want to print the strings read from the file but you are giving a[i] as an argument to printf() which is of type my_string and using %s format specifier to print it. The %s format specifier expect the argument to be a pointer to the initial element of an array of characters. That means the argument my_string is not the correct type for %s which is a undefined behavior. An undefined behavior includes it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.
From C Standards#7.21.6.1p9
If a conversion specification is invalid, the behavior is
undefined.282) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
[emphasis mine]
In your print() function you want to output the lines read from file, so the correct argument to printf() would be a[i].str.
void print(int count, my_string a[20]) {
for (int i = 0; i < count; i++) {
printf("%s\n", a[i].str);
}
}
Since you are new to C programming, make yourself aware of the undefined behavior (if you are not familiar with it).
There are few other issues in your program which another answer is already pointed out.

Segmentation Fault after reading a file into a struct array

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.

Pointer to a Pointer in C

I am writing a below Pro*C program and I am getting core dump error, could someone please help me what I am doing wrong. I am new to C
int main(int argc,char *argv[])
{
char inputpath1[300]="";
char inputpath2[300]="";
gets(inputpath1);
gets(inputpath2);
ExtractCmpFiles(inputpath1,inputpath2); //contains fullpath with file
return 0;
}
void ExtractCmpFiles(char *inputpath1,char *inputpath2)
{
int i=0;
char *strings[2];
strings[0]=malloc(sizeof(inputpath1)+1);
strcpy(strings[0],inputpath1);
strings[1]=malloc(sizeof(inputpath2)+1);
strcpy(strings[1],inputpath2);
printf("Your files are:\n%s\n%s\n",strings[0],strings[1]);//i am getting output here
char **holder='\0';
char ioarea[4096];
for(i=0;i<2;i++)
{
inFile=fopen(strings[i],"r");
if(!inFile)
{
fprintf(stderr,": Open failure for output file:");
fprintf(stderr,strings[i]);
fprintf(stderr,"\n");
}
holder=&strings[i];
holder=strrchr(strings[i],'/'); //checking the address of '/' to get only filename
holder++; //incrementing pointer
printf("your holder is: %s\n",*holder);
if(strncmp(holder,"bills",5)==0) //checking value from the pointer address is "bills" or not
{
//do as you wish
}
}
}
output:
/your/path/bills.cmp
/your/path/bill.cmp
Thank you all. I have modified the function as per suggestions, but still I am getting core dump error
Adding modified function:
void ExtractCmpFiles(char *inputpath1,char *inputpath2)
{
char *strings[2];
strings[0]=(char*)malloc(strlen(*inputpath1)+1);
strcpy(strings[0],inputpath1);
strings[1]=(char*)malloc(strlen(*inputpath2)+1);
strcpy(strings[1],inputpath2);
printf("Your files are:\n%s\n%s\n",strings[0],strings[1]);
char *holder=NULL;
char ioarea[4096];
int i=0;
for(i=0;i<2;i++)
{
inFile=fopen(strings[i],"r");
if(!inFile)
{
fprintf(stderr,": Open failure for output file:");
fprintf(stderr,strings[i]);
fprintf(stderr,"\n");
}
holder=strings[i];
holder=strrchr(strings[i],'/');
printf("i=%d --- %s\n",i,strings[i]); //when i=0 it is giving output then it is giving coredump
printf("your holder1 is: %s\n",holder);
holder++;
printf("your holder2 is: %s\n",holder);
if(strncmp(holder,"custbills",9)==0)
{
//do something
}
else
{
//do something
}
fclose(inFile);
}
The variable holder is a pointer to a pointer to char, and you assign to it the result of strrchr, a function that returns a pointer to char.
That will make holder no longer point to the array entry, so when you do holder++ it points somewhere else completely which leads to undefined behavior when you dereference holder. You then continue to pass holder to strncmp which again will give you undefined behavior.
The holder variable is not a character either, so you should not initialize it as one. If you want to initialize it you should initialize it to point to NULL.
The things mentioned above should make the compiler shout warnings at you.
Also, as noted in a comment by Cool Guy, if you want to get the length of a string you should use strlen. When you use sizeof you get the size of the pointer and not what it points to.
strings[0]=(char*)malloc(strlen(inputpath1));
strings[1]=(char*)malloc(strlen(inputpath2));
...
char *holder=NULL;
...
fclose(inFile);

No idea how I got this bug ~> C

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

Resources