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.
Related
I'm solving a coding problem for a Data Structures assignment, and one part of my solution keeps giving me a segfault: 11 when reading the last line of a text file using fgets().
I've already searched around StackOverflow for some time now and can't find the same error I'm getting. I've tried many ways to solve the problem but I can't figure out what exactly is wrong.
int main() {
**S = func();
free(S);
return 0;
}
char** func() {
FILE *fStrings = fopen("file.txt", "r");
if (fStrings == NULL) printf("Error opening 'file.txt'\n")
int length = fileLength("file.txt"); // This returns just the number of lines in a file, works as intended.
char **strings = (char **)malloc(200 * length * sizeof(char));
f(length, (char (*)[200])strings, *fStrings);
// some code using the data modified by f()
fclose(fStrings);
return strings;
}
void f(int length, char strings[][200], FILE *fStrings) {
int i;
for (i = 0; i <= length; i++) {
printf("i = %d\n", i); // debug
fgets(strings[i], 200, fStrings); // Here's the problem
printf("string = %s\n", strings[i]); // debug
}
}
The above code has 2 debug lines to see where exactly the error happens. The function is called with the correct parameters, where length is the amount of strings in the array, strings is an array of strings, and fStrings a file with said strings.
The segfault occurs when trying to read the last line of the text file. Any help will be appreciated.
EDIT: Changed the code block to include a better version of my code, in case it makes it easier to understand. The correct libraries are included too.
I think the main problem with your code is this line
for (i = 0; i <= length; i++) {
Due to <= it will loop "length + 1" times but you have only allocated memory for "length" times. Change it to:
for (i = 0; i < length; i++) {
Your allocation is strange. You should allocate a 2D array using a pointer to a 1D array, i.e. like this:
char (*strings)[200] = malloc(length * sizeof *strings)
then you can do the call without any cast.
Also just noticed this line:
f(length, (char (*)[200])strings, *fStrings);
^
notice
I don't think you want * in front of fStrings (it should not even compile with the *)
With the correct allocation (as described above) the call should be:
f(length, strings, fStrings);
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
This is probably trivial question. I am not a professional programmer, I am rather a mathematician who is doing some numerical experiment using C. I would like the output of my
experiment to be written in different files for different values of a parameter. MWE should do something like this. Crate a file pointer indexed by i. Open a file named file[i]. Write
i into that file and then close it. The code below obviously doesn't compile. Is such a construction even possible?
#include<stdio.h>
int i;
int
main()
{
for (i = 0; i < 10; i++){
FILE *f(i);
f(i)=fopen("file"[i],"w");
fprintf(f(i),"%d \n", i);
fclose(f(i));
}
return 0;
}
Edit: I got several decent answers but can somebody help to fix the sprintf problem. Namely on OpenBSD which I use sprintf is not recommended. So I get this message
$ gcc test.c
/tmp//ccN31aTv.o(.text+0x41): In function `main':
: warning: sprintf() is often misused, please use snprintf()
When I replace sprintf with snprintf I get all sorts of warnings
$ gcc test.c
test.c: In function 'main':
test.c:9: warning: passing argument 2 of 'snprintf' makes integer from pointer without a cast
test.c:9: warning: passing argument 3 of 'snprintf' makes pointer from integer without a cast
That doesn't look like a great quality code to me.
Final Solution: I just want to document final solution. ProPolice and systrace are happy with this code on OpenBSD. Thanks to everyone who helped!
#include<stdio.h>
int i;
char buf[20];
int
main()
{
for (i = 0; i < 10; i++){
snprintf(buf, sizeof(buf), "filename%d", i);
FILE *f = fopen( buf, "w");
fprintf(f,"%d \n", i);
fclose(f);
}
return 0;
}
In C, use snprintf:
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "file%d", i);
If you use linux, there is a useful GNU extension:
char *name;
asprintf(&name. "file%d", i);
You need to remember to free(name) after use.
Note that your syntax FILE *f(i); is not valid though.
If you need to declare an array of FILE * of 10 elements do:
FILE *array[10];
then use it like that:
array[i] = fopen(filename, "W");
Use sprintf to generate the filename.
char buf[80];
sprintf(buf,"file%d", i);
fopen(buf,"w");
Array syntax in C uses square brackets [].
You can just build a string up with sprintf. Make sure your buffer is large enough:
char filename[20];
sprintf( filename, "file%d", i );
Then you can open it like this:
FILE *f = fopen( filename, "w");
...
fclose(f);
No need to use an array (if that's what you were trying to do with f(i)), because you're only keeping one file open at a time.
If you want your files to be text-sortable, you might want file001, file002 etc... You can use %03d instead of %d to 0-pad to 3 digits.
You could try this:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i = 0;
for (i = 0; i < 10; i++) {
char filename[64];
sprintf(filename, "file%d", i);
FILE *fp = fopen(filename, "w");
fprintf(fp, "%d\n", i);
fclose(fp);
}
return 0;
}
Your code is almost ok. Some observations:
Use sprintf to create the name of the file. In C there is not a concatenate operator of strings.
You don't need to create an array of file pointers.
And of course, this may be improved: handling the size of the filename, padding the numbers, etc.
I'm sorry to bother you with this, but i'm stuck with it for too long already.
I get the following warning on fread: "warning: passing argument 1 of ‘fread’ makes pointer from integer without a cast"
I'm new to C and really like it, but don't get over this.
Thanks in advance.
typedef unsigned char byte;
int main( int argc, char *argv[]){
FILE * filein;
filein = fopen(argv[1], "r" );
int width=10;
int height=10;
byte ** data;
// Allocation
data = (byte **) malloc(height*sizeof(byte *));
for(int i=0;i<height;i++){
data[i]=(byte *) malloc(width*sizeof(byte));
}
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
fread(data[i][j], sizeof(const char), 1, infile);
}
}
for(int i=0;i<height;i++){
free(data[i]);
}
free(data);
fclose(filein);
return 0;
exit(0);
}
This is only a small piece of the actual program. The task is to read a binary pgm-image, store it in a data-matrix, normalize the values and write them to a new binary pgm-image.
fread() expects the void* pointer to the buffer. You are passing the value stored in data[i][j], not the pointer to the element data[i][j].
Try using the
fread(&data[i][j], sizeof(const char), 1, infile);
By the way, .pgm file format (if this is it) has a header and it is not sufficient to read only the width*height characters. The pixel values are also separated by spaces, so a little parsing is required. Also keep in mind that the end-of-line symbols also take space (.pgm cannot have more than 70 characters on one line)
The type of data[i][j] is byte. That is not a pointer. What you really want is to read to &data[i][j], if you're reading one byte at a time.
To read a single char, you can do
int c; // not char, because it must be able to hold EOF
c = getc(infile);
if( c == EOF ){
// do something about error or premature EOF
}
data[i][j] = c;
This is more verbose mostly because of the error checking that your code doesn't do.
Below is my code snippet
struct encode
{
char code[MAX];
}a[10];
int main()
{
char x[]={'3','0','2','5','9','3','1'};
for(i=0;i<1;i++)
{
printf("%c",x[i]);
//This will printout like 3025931 now I want this to be stored in structure.
}
strcpy(a[0].code,x);
// or
a[0].code=x;//neither works
display();
}
void display()
{
printf("%c",a[0].code);
}
I want the output to be like:3025931.
Which I am not getting due to incompatible assign type. Please tell me where am i going wrong.
I see two problems here. The first is that the source of the strcpy is a where it probably should be x.
The second is that x is not null-terminated. Strings in C are null-terminated character arrays.
I would change the two lines:
char x[] = {'3','0','2','5','9','3','1'};
strcpy(a[0].code, a);
to:
char x[] = {'3','0','2','5','9','3','1', '\0'};
strcpy(a[0].code, x);
Here's a complete program that gives you what you want (it actually prints out the number twice, once in your inner loop character by character and once with the printf so that you can see they're the same):
#include <stdio.h>
#include <string.h>
#define MAX 100
struct encode {
char code[MAX];
} a[10];
int main() {
int i, j;
char x[] = {'3','0','2','5','9','3','1','\0'};
for(i = 0; i < 1; i++) {
for(j = 0; j < 7; j++) {
printf("%c", x[j]);
}
printf("\n");
strcpy(a[0].code, x);
}
printf("%s\n",a[0].code);
return 0;
}
Update based on comment:
I am sorry. I am new to C. My apologies for not pasting the code snippet correctly in the beginning: "printf("%c",a[0].code);" doesn't display "3025931".
No, it won't. That's because a[0].code is a character array (string in this case) and you should be using "%s", not "%c". Changing the format specifier in the printf should fix that particular issue.
Here,
strcpy(a[0].code, a);
did you mean
strcpy(a[0].code, x);
...?
Also, x needs to be null terminated, or you need to replace strcpy with strncpy or memcpy and pass in a length.
This line doesn't make much sense:
strcpy(a[0].code, a);
Perhaps you want this:
memcpy(a[0].code, x, sizeof x);
a[0].code[sizeof x] = '\0';
(The second line is necessary to nul-terminate code, making it a proper C string).
A lot of things are wrong in your program. The most offending line is this:
strcpy(a[0].code, a);
but there are other oddities as well, e.g.
display is never called
a is only assigned (kind of), but never read (except in display, which is never called)
the i loop makes no sense
Basically, this program looks like copy-pasted by someone who has no clue.