I am having difficulty understanding why I am receiving an error with my C program. The main function makes a call to readFile() function which copies the contents of a text file to a 'Text' struct's 2D char array, then returns the struct. When I iterate through the struct array, I print the contents of the array without issue. But, when attempting to use a pointer to the struct and print the contents of the array, it prints garbage in certain cases.
The contents of my text.txt file is:
Hello world.
Hello galaxy.
Hello universe.
Goodbye.
And, Here is the code:
#include <stdio.h>
#include <stdlib.h>
struct Text {
char array[10][50];
};
struct Text readFile(char*);
int main(int argc, char *argv[]) {
int i, j;
char * file = argv[1];
struct Text text = readFile(file); // init Text struct w/call to readFile
struct Text * ptr_text = &text; // declare and init a ptr to struct
// print contents of 2D text array
for (i=0; i<sizeof(text.array) / sizeof(text.array[0]); i++) {
for (j=0; j<sizeof(text.array[0]); j++) {
printf("%c", text.array[i][j]);
if (text.array[i][j] == '\n') {
break; // breaks inner for loop & goes to next column in array
}
}
}
// same logic, but, w/ using a pointer to reference struct's array
for (i=0; i<sizeof(ptr_text->array) / sizeof(ptr_text->array[0]); i++) {
for (j=0; j<sizeof(ptr_text->array[0]); j++) {
printf("%c", ptr_text->array[i][j]);
if (ptr_text->array[i][j] == '\n') {
break; // breaks inner for loop & goes to next column in array
}
}
}
return 0;
}
// readFile function definition--
// reads text file, asigns contents to a 'Text'
// struct with a char array and returns its ptr
struct Text readFile(char* file) {
FILE *fp = NULL;
int col = 0;
int row = 0;
char c;
// declare Text struct & init w/ null chars
struct Text t = {{'\0'}};
fp = fopen(file,"r");
if (fp == NULL) {
exit(99);
}
printf("Reading File: %s\n", file);
// while loop assigns chars from file to Text struct's 2D array
while (1) {
if (feof(fp)) {
break;
}
c = getc(fp);
t.array[row][col] = c;
// if newline char, increment to next row in array, reset col to 0
if (c == '\n') {
row++;
col = 0;
continue;
}
// else, increment column in array
col++;
}
fclose(fp);
return t; // return Text struct
}
Program Output:
[cabox#Centos7-2 c]$ ./read_file1.o ./text.txt
Reading File: ./text.txt
Hello world.
Hello galaxy.
Hello universe.
Goodbye.
�Hello world.
Hello galaxy.
Hello universe.
Goodbye.
�
From the above, you can see that there are invalid (memory errors?) symbols when attempting to print the contents of the struct's array by using a pointer. So, clearly it has to do with my lack of understanding/incorrect use of a pointer. Sorry if this is a duplicate, I searched a good while for an answer to no avail.
EDIT:
Turns out, this has nothing to do with pointers afterall. As mentioned, I clearly didn't understand the proper use of feof(). Along with the suggestions, I had to add the following lines to the nested print loops:
if (ptr_text->array[i][j] == '\0') {
break;
}
Making the complete code for printing the loop:
for (i=0; i<sizeof(ptr_text->array) / sizeof(ptr_text->array[0]); i++) {
for (j=0; j<sizeof(ptr_text->array[0]); j++) {
if (ptr_text->array[i][j] == '\0') {
break;
}
printf("%c", ptr_text->array[i][j]);
if (ptr_text->array[i][j] == '\n') {
break; // breaks inner for loop & goes to next column in array
}
}
}
This way, when a null character in the array is reached, the program will continue to break the print loop (ultimately until main terminates), without printing anything that was not originally copied to the array via the call to readFile().
Thanks all for the quick replies!
For starters instead of this declaration
char c;
you have to write
int c;
And this while loop
while (1) {
if (feof(fp)) {
break;
}
c = getc(fp);
//...
also tries to write the EOF value in your array.
You need to rewrite the condition like for example
while ( ( c = getc(fp) ) != EOF )
and though the array within the structure is zero initialized
struct Text t = {{'\0'}};
nevertheless it is better to append each line with the terminating zero character '\0' explicitly. This will make your code clearer.
Related
I'm trying to read a file that contains a five letter word on each line for 12972 lines. I'm not sure why I'm getting this error even with freeing storage.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *file;
file = fopen("words.txt", "r"); // Opens file
char** gssArr = (char**)malloc(12972 * sizeof(char*)); // Allocates memory for 2d array
for(int i = 0; i < 12972; i++)
{
gssArr[i] = (char*)malloc(5 * sizeof(char));
}
char word[6]; // Current word being looked at from file
int current = 0; // Used for indexing x coordinate of 2d array
while(fgets(word,6,file) != NULL) // Not at end of file
{
if(word[0] != '\n') // Not at end of line
{
for(int j = 0; j < 5; j++) // Loops through all 5 letters in word, adding them to gssArr
{
gssArr[current][j] = word[j];
}
}
current++; // Index increase by 1
}
fclose(file); // Close file, free memory
free(gssArr);
FYI - your reader loop - you may want to make sure that your current index is not going beyond 12971.
Your problem is here:
current++;
Why?
Because it's done even when you are at the end of the line.
One solution is to move it inside the if statement but instead I'll recommend that you use fgets with a much larger buffer.
Details
If every line holds a five letter word then
fgets(word,6,file)
will read the five letters and zero terminate it. Then the next fgets will just read the "newline". Still you increment the index counter and in the end, you write outside allocated memory.
Try
while(fgets(word,6,file) != NULL) // Not at end of file
{
printf("current=%d\n", current);
and you see the problem.
To study for the exam we are trying to do some exercise from past exams.
In this exercise we get a header file and we have to create a function that read an input file and print onto the stdout only the parts of strings that do not contain digits.
(We have to pass the pointer of the string red to the main function).
We tried to do it with a an array but when printing the first word is empty or has strange characters. Instead doing a malloc allocation works fine.
What is also strange is that printing before everything an empty string will fix the code.
Therefore we don't understand why using an array of char the first word is not printed correctly, although it is saved in the buffer.
Including a printf before the while loop in the main function will reset the problem.
Using dynamic allocation (malloc) and not static allocation (array) will fix the print.
Iterating over the whole array and set all the memory to 0 does not fix the problem.
Therefore the pointer is correct as with printing an empty string it prints it correctly, but I really cannot understand what cause the issue.
Question are:
How it is possible that printing an empty string the print is correct?
Array is allocated on the stack therefore it is deallocated when the program exit the scope, why is only the first broken and not all the words?
#include "word_reader.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
const char * read_next_word(FILE * f) {
char buffer[WORD_MAX_LEN];
char * word = buffer;
for (int i = 0; i < WORD_MAX_LEN; ++i)
buffer[i] = 0;
//char * buffer = malloc(sizeof(char) * WORD_MAX_LEN);
int found = 0;
int c = 0;
int i = 0;
while (!found && c != EOF) {
while ((c = fgetc(f)) != EOF && isalpha(c)) {
found = 1;
buffer[i] = c;
++i;
}
buffer[i] = '\0';
}
if (found) {
return word;
//return buffer; // when use malloc
}
return 0;
}
int main(int argc, char * argv[]) {
FILE * f = fopen(argv[1], "r");
if(!f) {
perror(argv[1]);
return EXIT_FAILURE;
}
const char * word = 0;
//printf(""); // adding this line fix the problem
while ((word = read_next_word(f))) {
printf("%s\n", word);
}
fclose(f);
return 0;
}
the header file contain only the read_next_word declaration and define WORD_MAX_LEN to 1024. (Also include
the file to read (a simple .txt file)
ciao234 44242 toro
12Tiz23 where333
WEvo23
expected result:
ciao
toro
Tiz
where
WEvo
actual result
�rǫs+)co�0�*�E�L�mзx�<�/��d�c�q
toro
Tiz
where
WEvo
the first line is always some ascii characters or an empty line.
So I'm trying to write a code in C that would create an array of characters from a file looking like :
10 8
##########
###### ##
# $ $ ##
# # .# ##
# . #.# #
##$# * #
## #####
##########
But I'm stuck with a segmentation fault and I've been searching where it could come from unsuccessfully... I would really appreciate if someone could read my code and give me his/her feedback...
Thanks in advance !
//We define a structure representing a map (for the Sokoban game)
typedef struct map map;
struct map{
int width;
int height;
int x;
int y;// x and y are the position of the player
char* p_char; //p_char is pointing an array which will contain the elements of the map, the characters currently on the file above
};
//The function that reads the file and store the characters in an array
char* ReadMap(const char const* filename)
{
FILE* p_file = fopen(filename, "r");
char* p_array = NULL;
if (p_file = NULL) {
exit(EXIT_FAILURE);
}
else{
size_t size=1;
while (getc(p_file)!=EOF) {
size++;
}
p_array=(char*)malloc(sizeof(char)*size);
fseek(p_file,0,SEEK_SET);
for(size_t i=3; i<size-1; i++) {
p_array[i]=(char)getc(p_file);//i=3 cause we don't want the 2 first int, representing the size of the array
}
p_array[size-1]='\0';
fclose(p_file);
}
return p_array;
}
int main(int argc, char *argv[]){
if (argc != 2) {
fprintf(stderr, "You must provide a file name!\n");
exit(EXIT_FAILURE);
}
//We define a map structure
map map_loaded;
FILE *p_file1 = NULL;
p_file1=fopen(argv[1],"r");
if (p_file1==NULL) {
fprintf(stderr, "Cannot read file %s!\n", argv[1]);
exit(EXIT_FAILURE);
}
//we're trying to recover width and height, two int at the beginnning of the file
int width=0;
map_loaded.width=width;
int height=0;
map_loaded.height=height;
int fscanf_result=0;
fscanf_result=fscanf(p_file1, "%d %d\n", &width, &height);
char* p_char=NULL;
map_loaded.p_char=p_char;
p_char=ReadMap(argv[1]);
if (p_char != NULL) {
printf("%s\n", p_char);
free(p_char);
}
}
The cause of Segmentation Fault is the expression p_file = NULL used as condition.
p_file = NULL is an assignment expression. It sets p_file to NULL and evaluated to the assigned value, which is NULL.
NULL is treated as false when used as condition.
On the other hand, condition being false indicates file open success when the condition is a comparison p_file == NULL.
In this case, the condition becomes false when p_file is not NULL.
For that reason, code that expects that p_file is not NULL is written
in the else clause.
The code includes statements that pass p_file to fgetc().
As a result, NULL is passed to fgetc() and this is one possible reason of Segmentation Fault.
Note that your code still seems wrong after getting rid of this Segmentation Fault.
In the example, the size part is 10 8, which is 4-character long. This implies skipping "3 characters" doesn't make sense.
Also note that starting i from 3 won't skip file contents and just leave first 3 elements of the array uninitialized as Some programmer dude points.
Instead of that, you can "skip the first line". In other words, you can "skip until the first newline character".
size_t size=1;
int c;
while (getc(p_file)!=EOF) {
size++;
}
fseek(p_file,0,SEEK_SET);
while ((c=getc(p_file))!='\n' && c!=EOF) { // drop the first line
size--;
}
p_array=(char*)malloc(sizeof(char)*size);
if (p_array!=NULL) { // for in case malloc() fails
for(size_t i=0; i<size-1; i++) {
p_array[i]=(char)getc(p_file);
}
p_array[size-1]='\0';
}
fclose(p_file);
One way to enable width*i+j indexing is removing newline characters by adding this code after the line p_array[i]=(char)getc(p_file);:
if (p_array[i] == '\n') { // if the character is newline, remove it
i--; // rollback
size--; // adjust size for the newline character dropped
}
Let's say I've got the file
5f2
3f6
2f1
And the code:(The printf should print the second numbers (i.e 2,6, and 1) but it doesn't
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main (int argc, char * argv[])
{
FILE *ptr;
char str[100];
char * token;
int a, b, i;
int arr[4];
if(argc > 1)
{
ptr = fopen(argv[1],"r");
if(ptr == NULL)
{
exit(1);
}
}
else
{
exit(1);
}
//And I'm looking to parse the numbers between the "f" so..
while(fgets(str,100,ptr) != NULL)
{
token = strstr(str,"f");
if(token != NULL)
{
a = atol(str); // first number
b = atol(token+1); // second number
arr[i] = b; // store each b value (3 of em) into this array
}
i++;
printf("Values are %d\n",arr[i]); //should print 2,6 and 1
}
}
I've tried to move the printf outside the loop, but that seems to print an even weirder result, I've seen posts about storing integers from a file into an array before, however since this involves using strstr, I'm not exactly sure the procedure is the same.
int i,j=0;
while(fgets(str,sizeof(str),file) != NULL)
{
size_t n = strlen(str);
if(n>0 && str[n-1] == '\n')
str[n-1] = '\0';
i = str[strlen(str)-1] - '0'; /* Convert the character to int */
printf("%d\n",i);// Or save it to your int array arr[j++] = i;
}
Just move to the last character as shown and print it out as integer.
PS: fgets() comes with a newline character you need to suppress it as shown
You are never initializing i, then you are reading into arr[i] (which just happens to not crash right there), then increment i (to "undefined value + 1"), then print arr[i] -- i.e., you are writing to and reading from uninitialized memory.
Besides, your FILE * is ptr, not file. And you should get into the habit of using strtol() instead of atol(), because the former allows you to properly check for success (and recover from error).
Im writing a C code to read a file line by line which contains alphabets, CR,LF,'\0'. Below is my attached code sample. I want to store only alphabets from each line to an array such that the numbers of rows in the array equals no of lines in the file and column should be of varying length(depends on the number of character in i-th line).
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *buffer[100];
char temp[128];
int c,i=0,j=0;
int pos=0;
FILE *file;
file = fopen("input", "r");
if (file) {
while ((c = getc(file)) != EOF){
if ((c>=65 && c<=90) || (c>=97 && c<=122))
temp[pos++]=c;
else if(pos>1) {
temp[pos]='\0';
buffer[i]=temp;
printf ("%s\n",temp);
i++;
pos=0;
}
}
}
fclose(file);
while (j<i){
printf("%s\n",buffer[j]);
j++;
}
}
If i run my above code, all my buffer[j] contains same string.
Can anyone help me out in figuring what was wrong in the code.
buffer[] is an array of pointers, in your while loop you are pointing each of them to your array temp[]
buffer[i]=temp; // assign the address of temp to buffer[i]
Then you're changing the content of your temp[] array, but the address is always the same.
If you want to store the data from temp into each position in buffer[] you need to allocate memory and copy the data over there. More like:
buffer[i]=malloc(strlen(temp) + 1);
strcpy(buffer[i], temp);