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
}
Related
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.
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.
I am writing a program that streams words from a text file and puts them into an array. I've also added a display of array data to see if everything is ok but I get a segmentation fault after compiling.
I am new to system programming so I am aware I might have done some basic mistakes. Please find the code below and tell me where have I gone wrong.
#include <stdio.h>
#define BUFFER 100
int main() {
char tab[BUFFER];
FILE *wp;
wp = fopen("tab_file_b_words.txt", "r");
if(wp == NULL)
{
printf("error/n");
return -1;
}
int i;
for(i=0; i<sizeof(wp); i++) {
if(wp != NULL)
fscanf(wp, "%s", &tab[i]);
else
break;
}
printf("Content: \n");
for(i = 0; i < BUFFER; i++) {
if(tab[i] != NULL)
printf("%s\n", tab[i]);
else
break;
}
fclose(wp);
return 0;
}
As of now you are having array of char
what you need is
char tab[BUFFER]; --> char tab[BUFFER][SOME_LENGTH];
And
fscanf(wp, "%s", &tab[i]); --> fscanf(wp, "%s", tab[i]);
%s expects null terminated char * but you are passing char.
printf("%s\n", tab[i]);
sizeof(wp) is size of pointer.
for(i=0; i<sizeof(wp); i++)
What you need is
while (1 == fscanf(wp, "%s", tab[i]))
{
...
}
This section:
for(i=0; i<sizeof(wp); i++) {
if(wp != NULL)
fscanf(wp, "%s", &tab[i]);
else
break;
}
Is problematic.
First, there are a couple of issues with the line: fscanf(wp, "%s", &tab[i]); It should be written as:
fscanf(wp, "%s", tab); //removed & and array notation.
Unlike int or float variable types, the name of your char array (i.e. tab) is already a pointer pointing to the address of the variable, making it unnecessary (and incorrect) to use the address of operator (&).
Related to above... (and likely cause of segmentation fault.)
Because the definition of tab is for a simple array of char ( char tab[BUFFER]; ), the notation tab[i] refers only to the ith byte (or char) of the array, not the entire array. Because of the "%s" format specifier used, the function fscanf() expects a char * not a char, making tab the correct argument to use.
If you want to use an array of lines the variable must be created as a 2D array of char:
#define NUM_LINES 100
#define LINE_LEN 80
int main() {
char tab[NUM_LINES][LINE_LEN] = {{0}}; // zero initialized array of
// NUM_LINE strings
// each of LINE_LEN-1 capacity
In the statement for(i=0; i<sizeof(wp); i++) {
sizeof(wp)
will be equal to the number of bytes of the pointer wp, either 32 or 64 depending on the target addressing of your application. This is probably not what you intended. (or want.)
Consider a different approach:
Given you are working with text files, try using a combination of while() and fgets() to read lines from the file. Then you can process each line based on its known syntax.
(Following example uses a single dimension char array for simplified illustration.)
char line[some_len];
wp = fopen(some_file_name, "r");
if(wp)
{
while(fgets(line, some_len, wp))
{
// use line. In this case, just print to stdout
printf("%s\n", line);
}
fclose(wp);
}
sizeof(wp) is the problem.
sizeof returns the length of a type in bytes and not the length of the file.
If you want to get the size of a file this may help you.
I have following struct
typedef struct
{
char* city;
int temp;
} Place;`
I am attempting to read in two values from a line into an array of structs.
The lines look like:
Los Angeles; 88
I am attempting to read data into the array. Assuming my memory allocation is correct what is the correct way to read in these values.
my code
void readData(FILE** fpData, FILE** fpOutput)
{
char s[100];
int index = 0;
Place *values;
values=malloc(size * sizeof(Place));
if (values == NULL)
{
MEM_ERROR;
exit(1);
}
for (int a = 0; a < size; a++)
{
(values[a]).city = (char *) malloc(100 * sizeof(char));
if(values[a].city == NULL)
{
MEM_ERROR;
exit(100);
}
}
while(fgets(s, sizeof(s), *fpData)!=NULL)
{
sscanf(s, "%[^:]%*c%d\n", values[index].city, &values[index].temp);
index++;
}
sortInsertion(values, size, fpOutput);
free(values);
return;
}
The city is not going into the array so I am assuming the part where it says values[index].city is incorrect.
How can I fix this ?
Your data using semicolon ; while your sscanf format using colon :, make sure this is same character. If your data really use semicolon, change %[^:] part in the sscanf format to %[^;]
Here my code and how I run it to show you that it works:
#include <stdio.h>
struct Place {
char city[100];
int temp;
} values[30];
int main() {
char s[100];
int i=0, n=0;
while ( fgets(s, sizeof(s), stdin) != NULL ) {
sscanf(s, "%[^;]%*c%d\n", values[n].city, &values[n].temp);
n++;
}
printf("n=%d\n", n);
for ( i=0; i<n; i++ ) {
printf("values[%d] = (%s, %d)\n", i, values[i].city, values[i].temp);
}
}
This is how I run it on Linux:
% for a in `seq 1 3`; do echo "City-$a; $a$a"; done | ./a.out
n=3
values[0] = (City-1, 11)
values[1] = (City-2, 22)
values[2] = (City-3, 33)
sscanf(s, "%[^:]%*c%d\n", values[index].city, &values[index].temp);
This will copy everything from the start of the line read up to the first colon (:) into the city array you allocated. Your example input would seem to have a semi-colon (;), so you'll get the entire line in the city array and nothing in the temp field.
You don't do any input checking, so any too-long input line will get split into multiple (probably corrupted) cities. You'll also have problems if there are not exactly size lines in the file, as you don't check to make sure index doesn't go past size while reading, and you assume you have size entries at the end without checking.
I'm very new to C and I'm still learning the basics. I'm creating an application that reads in a text file and breaks down the words individually. My intention will be to count the amount of times each word occurs.
Anyway, the last do-while loop in the code below executes fine, and then crashes. This loop prints memory address to this word (pointer) and then prints the word. It accomplishes this fine, and then crashes on the last iteration. My intention is to push this memory address into a singly linked list, albeit once it's stopped crashing.
Also, just a quick mention regarding the array sizes below; I yet figured out how to set the correct size needed to hold the word character array etc because you must define the size before the array is filled, and I don't know how to do this. Hence why I've set them to 1024.
#include<stdio.h>
#include<string.h>
int main (int argc, char **argv) {
FILE * pFile;
int c;
int n = 0;
char *wp;
char wordArray[1024];
char delims[] = " "; // delims spaces in the word array.
char *result = NULL;
result = strtok(wordArray, delims);
char holder[1024];
pFile=fopen (argv[1],"r");
if (pFile == NULL) perror ("Error opening file");
else {
do {
c = fgetc (pFile);
wordArray[n] = c;
n++;
} while (c != EOF);
n = 0;
fclose (pFile);
do {
result = strtok(NULL, delims);
holder[n] = *result; // holder stores the value of 'result', which should be a word.
wp = &holder[n]; // wp points to the address of 'holder' which holds the 'result'.
n++;
printf("Pointer value = %d\n", wp); // Prints the address of holder.
printf("Result is \"%s\"\n", result); // Prints the 'result' which is a word from the array.
//sl_push_front(&wp); // Push address onto stack.
} while (result != NULL);
}
return 0;
}
Please ignore the bad program structure, as I mentioned, I'm new to this!
Thanks
As others have pointed out, your second loop attempts to dereference result before you check for it being NULL. Restructure your code as follows:
result = strtok( wordArray, delims ); // do this *after* you have read data into
// wordArray
while( result != NULL )
{
holder[n] = *result;
...
result = strtok( NULL, delims );
}
Although...
You're attempting to read the entire contents of the file into memory before breaking it up into words; that's not going to work for files bigger than the size of your buffer (currently 1K). If I may make a suggestion, change your code such that you're reading individual words as you go. Here's an example that breaks the input stream up into words delimited by whitespace (blanks, newlines, tabs, etc.) and punctuation (period, comma, etc.):
#include <stdio.h>
#include <ctype.h>
int main(int argc, char **argv)
{
char buffer[1024];
int c;
size_t n = 0;
FILE *input = stdin;
if( argc > 1 )
{
input = fopen( argv[1], "r");
if (!input)
input = stdin;
}
while(( c = fgetc(input)) != EOF )
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
fclose(input);
return 0;
}
No warranties express or implied (having pounded this out before 7:00 a.m.). But it should give you a flavor of how to parse a file as you go. If nothing else, it avoids using strtok, which is not the greatest of tools for parsing input. You should be able to adapt this general structure to your code. For best results, you should abstract that out into its own function:
int getNextWord(FILE *stream, char *buf, size_t bufsize)
{
int c;
size_t n = 0;
while(( c = fgetc(input)) != EOF && n < bufsize)
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buf[n] = 0;
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
if (n == 0)
return 0;
else
return 1;
}
and you would call it like
void foo(void)
{
char word[SOME_SIZE];
...
while (getNextWord(inFile, word, sizeof word))
{
do_something_with(word);
}
...
}
If you expect in your do...while code, that result could be null (this is the condition for loop break), how do you think this code-line:
holder[n] = *result;
must work? It seems to me, that it is the reason for crashing in your program.
Change do while loop to while
use
while (condition)
{
}
instead of
do {
}while(condition)
It is crashing because you are trying to derefrance a NULL pointer result in do while loop.
I work mostly with Objective-C and was just looking at your question for fun, but I may have a solution.
Before setting n=0; after your first do-while loop, create another variable called totalWords and set it equal to n, totalWords can be declared anywhere within the file (except within one of the do-while loops), but can be defined at the top to the else block since its lifetime is short:
totalWords = n;
then you can set n back to zero:
n = 0;
Your conditional for the final do-while loop should then say:
...
} while (n <= ++totalWords);
The logic behind the application will thus say, count the words in the file (there are n words, which is the totalWords in the file). When program prints the results to the console, it will run the second do-while loop, which will run until n is one result past the value of totalWords (this ensures that you print the final word).
Alternately, it is better practice and clearer for other programmers to use a loop and a half:
do {
result = strtok(NULL, delims);
holder[n] = *result;
wp = &holder[n];
printf("Pointer value = %d\n", wp);
printf("Result is \"%s\"\n", result);
//sl_push_front(&wp); // Push address onto stack.
if (n == totalWords) break; // This forces the program to exit the do-while after we have printed the last word
n++; // We only need to increment if we have not reached the last word
// if our logic is bad, we will enter an infinite loop, which will tell us while testing that our logic is bad.
} while (true);