reading ppm file with fread in C - c

I am reading a ppm file with fread and getting the things which are not in the file. My code is as follows:
typedef struct {
int red;
int green;
int blue;
} Pixel;
typedef struct {
int width;
int height;
int max_value;
Pixel *p;
} Image;
Image* read_image(char *filename)
{
char buff[16];
Image *img;
FILE *fp;
int c, rgb_comp_color;
//open PPM file for reading
fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
}
//read image format
if (!fgets(buff, sizeof(buff), fp)) {
perror(filename);
exit(1);
}
//check the image format
if (buff[0] != 'P' || buff[1] != '3') {
fprintf(stderr, "Invalid image format (must be 'P3')\n");
exit(1);
}
//alloc memory form image
img = (Image *)malloc(sizeof(Image));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
//read image size information
if (fscanf(fp, "%d %d", &img->width, &img->height) != 2) {
fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
exit(1);
}
//read rgb component
if (fscanf(fp, "%d", &img->max_value) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
}
while (fgetc(fp) != '\n') ;
//memory allocation for pixel data
img->p = (Pixel*)malloc(img->width * img->height * sizeof(Pixel));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
//read pixel data from file
if (fread(img->p, 3 * img->width, img->height, fp) != img->height) {
fprintf(stderr, "Error loading image '%s'\n", filename);
exit(1);
}
fclose(fp);
return img;
}
void print_image(Image *img){
printf("P3\n");
printf("%d %d\n", img->width, img->height);
printf("%d\n", img->max_value);
for(int i=0; i<img->width*img->height; i++)
printf("%d %d %d ", img->p[i].red, img->p[i].green, img->p[i].blue);
printf("\n");
}
When I try to read this file:
P3
7
7
15
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15
0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0
0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15
0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0
0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
The result of my read_image is this (I print the result by print_image function):
P3
7 7
15
538980362 540024864 807411744 538976288 538980361 540024864 807411744 538976288 538980361 540024864 807411744 538976288 538980361 540024864 807411744 538976288 538980361 540024864 807411744 538976288 538980361 540024864 807411744 538976288 538980361 540024864 807411744 538976288 540019209 857743392 538976288 538976307 540215584 857743392 538976288 538976304 3148064 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Am I using the fread wrong or what part of the proccess am I missing?
Thanks, in advance.

IIRC, in a .ppm file, the geometry/format can be on multiple lines [or a single line].
So, doing fgets to read it won't work. Use fscanf for the entire format instead.
Also, IIRC, the actual data is packed binary, so your test file isn't really a PPM [if it truly has ascii text for the pixel values as your data block seems to show].
The real format for the data doesn't have embedded newlines, so you can't do the fgetc, just do fread.
See my answer: How to do a black-and-white picture of a ppm file in C?

Related

fgetc read only 39 bytes from file

This programm reads only 39 bytes. After this everything reads as '-1'
#include <windows.h>
#include <stdio.h>
int main()
{
FILE *file =fopen("Eva.wav","r");
if (file==NULL)
printf("heresy read!");
for(int i=0;i<200;i++)
{
char a = fgetc(file);
printf("%hhX ",a);
}
fclose(file);
return 0;
}
enter image description here
I rewrite code using fread function. After 39 byte comes something absolute other byte code. Looks like segmented file. But if it so, why fread and fgets result are different?
C:\Users\phoenix\Documents\gccex\serial>a.exe
52 49 46 46 46 FF8C FFA3 0 57 41 56 45 66 6D 74 20 10 0 0 0 1 0 1 0 44 FFAC 0 0 44 FFAC 0 0 1 0 8 0 4C 49 53 54 FF86 FFAA 6A FFFB FFFE 7F 0 0 FF88 2C 40 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 40 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 1 10 0 0 0 0 60 7 FF96 0 0 0 0 0 FF86 FFAA 6A FFFB FFFE 7F 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 FFB0 16 40 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 13 FF96 0 0 0 0 0 FF83 16 40 0 0 0 0 0 1 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 70 13 FF96 0 0 0 0 0 FFB0 16 40 0 0 0 0 0 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FF99 17 40 0 0 0 0 0 10 0 0 0 0 0 0 0 FF99 16 40 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0
What is the right way to read file?
On Microsoft Windows, binary files should be opened in binary mode ("rb"), not text mode ("r"). A WAVE file is a binary file.
After this everything reads as '-1'
This statement is incorrect. You are no longer reading anything. The function fgetc is returning the macro constant EOF, which is defined as -1 on most platforms. This should become apparant if you check for EOF, by changing your loop to the following:
for(int i=0;i<200;i++)
{
int a = fgetc(file); //the type must be int, not char
if ( a == EOF )
{
printf( "EOF\n" );
break;
}
printf("%hhX ",a);
}
When fgetc returns EOF, this means that either end-of-file has been reached or an error has occurred. In this case, it is due to end-of-file.
On Microsoft Windows, when a file is opened in text mode, the character code 0x1A is interpreted as the end of the file. According to your posted screenshot, your file happens to have the value 0x1A at file offset 0x28. That is the reason why you can only read up to file offset 0x27 (39 in decimal) in the file. To fix this, open the file in binary mode instead of text mode.
"What is the right way to read file?"
Annotated example below:
// #include <windows.h> // Not needed for this program
#include <stdio.h>
int main() {
char *fname = "Eva.wav"; // re-usable string
FILE *file = fopen( fname, "rb" ); // NB: "binary mode" for Windows
if( file == NULL ) {
fprintf( stderr, "Cannot open '%s'\n", fname ); // See?
exit( EXIT_FAILURE ); // do not continue
}
unsigned char buf[ 200 ]; // OP wants to 'sniff' first 200 bytes
// "correct" way to read bytes
// Could use loop, reading 1, 20, or 50 bytes at a time. Why?
size_t nRead = fread( buf, sizeof buf[0], sizeof buf, file );
fclose( file ); // close when no longer needed
// only bytes loaded, not quantity expected
for( size_t i = 0; i < nRead; i++ )
printf( "%02X ", buf [ i ] ); // "old school". may be antiquated
return 0;
}

2D array - I want to find which columns have 1s in them in each row

My input looks like this :
15 5
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
1 0 0 0 0
0 1 0 1 0
0 0 1 0 0
0 0 0 0 1
0 0 0 0 0
0 0 0 0 0
0 1 0 0 0
1 0 0 0 1
0 0 1 0 0
0 0 0 1 0
The first row contains the number of rows and columns of my array. And basically I want to find out where these 1s are in the array.
So in the first 3 rows i want to get 3, in the 7th 1, and in the 8th, i want to get 2 3 etc..
My code looks like this so far
#include <stdio.h>
int main() {
int row, column;
FILE* input;
FILE* output;
input = fopen("input.txt", "r");
if (input == 0) {
printf("ERROR couldn't open input.txt");
return 1;
}
if (! fscanf(input, "%d %d", &row, &column)) {
printf("ERROR not recognised value");
fclose(input);
return 2;
}
output = fopen("output.txt", "w");
int meteor[row][column];
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
fscanf(input, "%d", &meteor[i][j]);
}
}
int sum;
int loc[row];
for (int i = 0; i < row; i++) {
sum = 0;
for (int j = 0; j < column; j++) {
sum += meteor[i][j];
if (meteor[i][j] == 1) {
loc[i] = (j + 1);
}
}
printf("%d %d\n", loc[i], sum);
}
fclose(input);
fclose(output);
return 0;
}
My output is this :
3 1
3 1
3 1
0 0
-1 0
1 1
4 2
3 1
5 1
0 0
4214921 0
2 1
5 2
3 1
4 1
The first column shows some of the locations, the second shows how many 1s are in the row, but it all fails when there are only 0s in the row or there is more than one 1. And also I would like to store these values.
You need to initialize loc[].. If you look carefully at your code, you only populate it on the condition of if (meteor[i][j] == 1)... but you print it for every index of i. which would print uninitialized memory (i.e. unknown).
To answer the second part of your question, if you want to store the "sum". Simply make loc[] a 2d array just like meteor, but with 2 columns (row and sum). i.e. int loc[row][2].. making sure to initialize both columns of course :)

Updating a matrix with special cases

I am trying to write a function which gets a matrix 9x9 and updates it accordingly to user's input with the following rules:
Valid number is between 1 and 9 (zero is invalid).
I have to use scanf until I get EOF.
Input has digits and symbols. valid input is a pair of two digits following with a symbol or EOF or space. string with more than two digits is invalid. for example (123% isn't valid but 12% is valid).
Example:
Input: 10 33%55^21 $123%
Output:
0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
Explanation: 10 and 123 are invalid. 33, 55 and 21 are valid so we will put 1 in 22, 44 and 10.
What I tried to do:
void updateMarix(int matrix[][9]) {
int digits = 0, one_previous, two_previous;
char input;
while (scanf("%c", &input) != EOF) {
if(isValidDigit(input)) {
digits++;
if(digits == 1) {
two_previous = input - '0' - 1;
continue;
} else if(digits == 2){
one_previous = input - '0' -1;
continue;
}
} else if(digits == 2) {
matrix[two_previous][one_previous]++;
}
digits = 0; // reset
}
}
most tests are end with success, but some of them are fail. I think that is because I don't handle with the last input (if for example it ends with 22 it won't update it because with my implementation, the update is in the next iteration when other symbol got as input).
Is there a better implementation for this? My code became messy and not clean.
*Edit: It should ignore invalid input and a3b doesn't counts, a03b also doesn't counts but a13b does counts as 13 meaning we should increase the number in matrix[0][2].
Edit 2: #JonathanLeffler menationed FSM so I tried to create one:
Although it doesn't handles the case of 1234 (invalid number) or 123 (also invalid). The most similar thing was to create an arrow from second number to symbol (but it isn't quite true because in 1234%12 only 12 is valid.
I think your FSM needs 4 states plus the end state:
Zero digits read (D0).
One digit read (D1).
Two digits read (D2).
Digits are invalid but no more error reporting needed (DI).
There are 4 different inputs, too:
Digit 1-9.
Digit 0.
Other.
EOF.
I've used a switch on state and if/else code in each state, but it leads to somewhat verbose code. OTOH, I believe it handles inputs correctly.
/*
** FSM
** States: 0 digits (D0), 1 digit (D1), 2 digits (D2), digits invalid (DI)
** Inputs: digit 1-9 (D), digit 0 (0), other (O), EOF.
** Action: S - save, E - error, I - ignore, P - print
** Body of FSM encodes "action;state"
**
** State D0 D1 D2 DI
** Input
** D S;D1 S;D2 E;D2 I;DI
** O I;D0 E;D0 P;D0 I;D0
** 0 E;D2 E;D2 E;D2 I;DI
** EOF I;end E;end P;end I;end
*/
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
enum State { D0, D1, D2, DI };
enum Input { Digit, Zero, Other, End };
static int debug = 0;
static enum Input input(int *rv)
{
int c = getchar();
if (debug)
printf("Input: %c\n", (c == EOF) ? 'X' : c);
*rv = c;
if (c == EOF)
return End;
if (isdigit(c))
{
*rv = c - '0';
return (c == '0') ? Zero : Digit;
}
return Other;
}
static void updateMatrix(int matrix[9][9])
{
char pair[2] = { 0, 0 };
enum State state = D0;
int c;
enum Input value;
while ((value = input(&c)) != End)
{
switch (state)
{
case D0:
if (value == Digit)
{
pair[0] = c;
state = D1;
}
else if (value == Zero)
{
fprintf(stderr, "Received zero digit - invalid\n");
state = DI;
}
else
{
assert(value == Other);
}
break;
case D1:
if (value == Digit)
{
pair[1] = c;
state = D2;
}
else if (value == Zero)
{
fprintf(stderr, "Received zero digit - invalid\n");
state = DI;
}
else
{
assert(value == Other);
fprintf(stderr, "Received one digit where two expected\n");
state = D0;
}
break;
case D2:
if (value == Digit)
{
fprintf(stderr, "Received more than two digits where two were expected\n");
state = DI;
}
else if (value == Zero)
{
fprintf(stderr, "Received zero digit - invalid\n");
state = DI;
}
else
{
assert(value == Other);
printf("Valid number %d%d\n", pair[0], pair[1]);
matrix[pair[0]-1][pair[1]-1] = 1;
state = D0;
}
break;
case DI:
if (value == Other)
state = D0;
break;
}
}
if (state == D2)
{
printf("Valid number %d%d\n", pair[0], pair[1]);
matrix[pair[0]-1][pair[1]-1] = 1;
}
else if (state == D1)
fprintf(stderr, "Received one digit where two expected\n");
}
static void dump_matrix(const char *tag, int matrix[9][9])
{
printf("%s:\n", tag);
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
printf("%4d", matrix[i][j]);
putchar('\n');
}
}
int main(void)
{
int matrix[9][9] = { 0 };
updateMatrix(matrix);
dump_matrix("After input", matrix);
return 0;
}
On your test input, it produces the output:
Received zero digit - invalid
Valid number 33
Valid number 55
Valid number 21
Received more than two digits where two were expected
After input:
0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
On the mostly-invalid input file:
123345132
bbbb12cccc1dddd011dd
it produces the output:
Received more than two digits where two were expected
Valid number 12
Received one digit where two expected
Received zero digit - invalid
After input:
0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
You can argue (easily) that the error messages could be more informative (identifying the erroneous character, and possibly the prior valid digits), but it only produces one error message for each invalid sequence, which is beneficial.
You could use a combination of fgets(), sscanf() and strpbrk() for this.
The input line is read into a character array str and a pointer ptr pointing to the part of the string in str being processed is maintained.
First, set up a loop to read input line by line. fgets() will return NULL on EOF.
for(; fgets(str, sizeof(str), stdin); )
{
...
...
...
}
fgets() will read in the trailing newline as well. You could remove it like
str[strlen(str)-1]='\0';
Now inside the above loop, use another loop to process the input line in str like
for(ptr=str; (ptr=strpbrk(ptr, "0123456789"))!=NULL; ptr+=len)
{
sscanf(ptr, "%d%n", &n, &len);
if(n>10 && n<100)
{
//accepted
printf("\n%d", n);
arr[n/10][n%10]=1;
}
//else discarded
}
strpbrk()'s prototype is
char *strpbrk(const char *s1, const char *s2);
and it returns a pointer to the first character in s1 which is a character in the string s2. If there is no match, NULL is returned.
So we are looking to see the first digit part in str that remains to be processed with strpbrk(ptr, "0123456789").
This number part is read into n via sscanf(). If this number is in the range you need, you may accept it.
The %n format specifier is used to find out the number of characters which has been scanned with the sscanf() inorder to find the value by which ptr must be updated. See this post.
The digit in the ones place will be n%10 and that in the tens place will be n/10 as the number you need is a 2-digit number.
You may set your array representing the matrix like
arr[n/10][n%10]=1;
So the whole thing could look something like
char *ptr, str[50];
for(; fgets(str, sizeof(str), stdin); )
{
for(ptr=str, str[strlen(str)-1]=0; (ptr=strpbrk(ptr, "0123456789"))!=NULL; ptr+=len)
{
sscanf(ptr, "%d%n", &n, &len);
if(n>10 && n<100)
{
printf("\n%d", n);
arr[n/10][n%10]=1;
}
}
}
And for your input 10 33%55^21 $123%, the output would be
33
55
21
as 10 and 123 will be discarded.

C read big matrix from input file

Im trying to read a 40000x40000 boolean (binary) matrix from a input file and store it in a variable. After I store it in the variable, I want to write it to a file. However, with the code I wrote it takes more than a hour. Can someone help me out? I think im doing something wrong.
Code
void get_grid_values_file(bool *grid, int n, int m, char *input_filename){
FILE *in_file;
in_file = fopen(input_filename, "r");
char buffer[1];
bool search = true;
int k=0;
while(search){
fseek(in_file, k, SEEK_SET);
fread(buffer, 1, 1, in_file);
if(*buffer == '\n')
search = false;
k++;
}
int i,j;
for(i=0; i<n; i++){
for(j=0; j<m; j++){
fseek(in_file, k, SEEK_SET);
fread(buffer, 1, 1, in_file);
*((grid+i*m) + j) = atof(buffer);
k+=2;
}
}
fclose(in_file);
}
void set_grid_values_file(bool *grid, int n, int m, char *output_filename){
FILE *out_file;
out_file = fopen(output_filename, "w");
char buffer[1] = " ";
//Set n,m and spaces
int length_n= (int) (log10 (abs (n))) + 1;
char char_n[length_n];
sprintf(char_n, "%d", n);
fseek(out_file, 0, SEEK_SET);
fwrite (char_n, length_n, 1, out_file);
fseek(out_file, length_n, SEEK_SET);
fwrite (" ", 1, 1, out_file);
int length_m= (int) (log10 (abs (m))) + 1;
char char_m[length_m];
sprintf(char_m, "%d", m);
fseek(out_file, length_n+1, SEEK_SET);
fwrite (char_m, length_m, 1, out_file);
fseek(out_file, length_n+1+length_m, SEEK_SET);
fwrite ("\n", sizeof(char), 1, out_file);
//Set grid
int i,j;
int k =length_n + length_m + 2;
for(i=0; i<n; i++){
for(j=0; j<m; j++){
fseek(out_file, k, SEEK_SET);
buffer[0] = (*((grid+i*m) + j) == true ? '1' : '0');
fwrite (buffer, 1, 1, out_file);
k++;
fseek(out_file, k, SEEK_SET);
fwrite (" ", 1, 1, out_file);
k++;
}
fseek(out_file, k, SEEK_SET);
fwrite ("\n", sizeof(char), 1, out_file);
k++;
}
}
int main(int argc, char *argv[])
{
char *input_filename = "gen0_40kx40k.in";
char *output_filename = "gol_output.out";
int n = 40000;
int m = 40000;
bool *grid = (bool *)malloc(n*m*sizeof(bool));
//Read
get_grid_values_file((bool *)grid, n, m, input_filename);
//Write
set_grid_values_file((bool *)grid, n, m, output_filename);
return 0;
}
Input format, the first line contains the dem of the 2d matrix:
20 20
1 0 1 0 0 1 0 0 1 0 1 0 1 0 1 1 0 1 0 0
1 1 0 0 0 0 0 1 0 1 1 1 1 0 0 1 0 0 1 1
0 1 1 0 1 0 1 1 0 0 0 1 1 0 0 1 1 0 0 1
1 0 1 1 0 1 0 0 1 0 1 1 1 0 1 0 1 1 1 1
1 1 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 1 1 1
1 1 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0 1 0 1
1 1 1 0 0 0 1 1 1 0 0 1 1 1 1 1 0 0 1 1
0 1 0 1 1 1 1 1 0 1 0 1 0 1 1 1 1 0 0 1
1 0 0 0 0 1 1 0 1 1 1 1 0 1 1 1 0 0 0 0
1 1 0 0 0 1 1 0 0 1 1 1 1 1 1 1 0 1 1 0
0 1 1 0 0 0 1 1 0 1 1 0 0 1 0 1 1 1 1 1
0 0 0 1 1 1 1 1 0 0 1 0 1 1 0 0 1 1 1 0
1 0 0 1 0 0 0 1 1 1 0 1 1 0 0 0 1 1 0 0
0 1 0 1 0 1 1 0 0 0 0 1 1 0 1 1 0 1 0 1
1 0 0 0 0 0 1 1 0 1 1 0 0 0 1 1 1 1 1 1
1 1 1 0 1 0 1 1 1 1 0 0 1 0 1 1 0 0 1 0
1 0 0 1 0 0 0 1 1 1 1 0 0 0 1 1 0 0 0 1
0 0 0 1 0 1 1 1 1 0 1 0 0 0 1 1 0 0 0 1
1 1 1 0 1 0 1 1 1 0 1 1 0 1 0 1 0 1 0 1
1 1 1 0 1 0 1 1 0 1 0 0 1 0 0 0 0 1 0 1
Read larger chunks from the input file - not every char as a separate call. Eg a complete row of your matrix at once.
Why do you use in the inner loop of set_grid_values_file two fwrite calls. Better to combine them:
char buffer[2] = " ";
for(i=0; i<n; i++){
int base = grid+i*m;
for(j=0; j<m; j++){
fseek(out_file, k, SEEK_SET);
buffer[0] = (*(base + j) ? '1' : '0');
fwrite (buffer, 1, 2, out_file);
k+=2;
}
I would suggest removing the calls to fseek.
while(search){
// Make sure the read is successful. Otherwise, break out of the loop.
if ( fread(buffer, 1, 1, in_file) != 1 )
{
break;
}
if(*buffer == '\n')
search = false;
k++;
}
int i,j;
// Rewind the file
fseek(in_file, 0, SEEK_SET);
for(i=0; i<n; i++){
for(j=0; j<m; j++){
// Make sure the read is successful. Otherwise, break out of the loop.
if ( fread(buffer, 1, 1, in_file) != 1 )
{
break;
}
*((grid+i*m) + j) = atof(buffer);
k+=2;
}
}
Also atof(buffer) is a problem when buffer has only one element in it. Use at least a two element array.
char buffer[2] = {0};
This is about the simplest(and possibly the fastest) method.
stdio is buffered, getc() is most probably a macro
function calls are costly (they trash the instruction pipeline and cache) ; you use 1seek+1fread per boolean bit read.
you dont need to seek the file; just read it sequentially and put the values at the correct{row,col} positions.
setting and testing an indicator variable (your search) is a waste of time (often taught in Pascal and Java classes...) ;instead: just jump out of the loop (or continue)
I am assuming an ASCII file with spaces between the values, but without the{nrow,ncol} at the top (the{n,m}values are supplied as function arguments)
void get_grid_values_file(bool *grid, int n, int m, char *input_filename)
{
unsigned col,row;
FILE * fp;
fp= fopen (input_filename, "r" );
if(!fp)return;
for(row=col=0; ; ) {
int ch;
ch=getc(fp);
if (ch == EOF)break;
if (ch < '0' || ch > '1') continue;
grid[row*m+col++] = (ch == '0') ? False :True;
if (col == m) {col=0; row++; }
if (row == n) break;
}
fclose(fp);
return;
}

Using C, While initializing an array of structs, it seems like the first column, and the last column are overlooping

When main runs, I've been getting this output. The first columns being somehow confused with the last one, even though it's specifically initialized.
0 0 0 0 0 0 4 3 13 3 3 0 0 0 0 0 0
0 0 0 0 0 4 0 0 5 0 0 2 0 0 0 0 0
0 0 0 0 4 0 0 0 5 0 0 0 2 0 0 0 0
0 0 0 18 0 0 0 0 5 0 0 0 0 17 0 0 0
0 0 4 0 2 0 7 12 19 12 3 0 8 0 2 0 0
0 4 0 0 0 0 0 0 5 0 0 0 0 0 0 2 0
0 0 0 0 5 0 0 0 5 0 0 0 5 0 0 0 2
2 0 0 0 11 0 0 0 5 0 0 0 11 0 0 0 1
1 7 7 7 20 7 7 7 14 7 7 7 20 7 7 7 1
1 0 0 0 11 0 0 0 5 0 0 0 11 0 0 0 1
1 0 0 0 1 0 0 0 5 0 0 0 1 0 0 0 0
0 6 0 0 0 0 0 0 5 0 0 0 0 0 0 8 0
0 0 6 0 4 0 7 12 19 12 3 0 6 0 8 0 0
0 0 0 15 0 0 0 0 5 0 0 0 0 16 0 0 0
0 0 0 0 6 0 0 0 5 0 0 0 8 0 0 0 0
0 0 0 0 0 6 0 0 5 0 0 8 0 0 0 0 0
0 0 0 0 0 0 7 7 7 7 8 0 0 0 0 0 0
motion.h
struct square{
int directions;
int isRobotHere;
int isMultipleDirections;
int printable;
};
typedef struct square Square;
struct robot{
int robotx;
int roboty;
int robotz;
int destinationx;
int destinationy;
int destinationz;
};
typedef struct robot Robot;
enum direction{North, NorthWest, West, SouthWest, South, SouthEast, East, NorthEast};
Square firstfloor[16][16];
Square secondfloor[16][16];
void printbothfloors();
void initializeArrays();
initializeArrays.c
#include <stdio.h>
#include "motion.h"
void initializeArrays(){
firstfloor[6][0].directions=5;
firstfloor[7][0].directions=5;
firstfloor[8][0].directions=14;
firstfloor[9][0].directions=5;
firstfloor[10][0].directions=6;
firstfloor[11][1].directions=6;
firstfloor[12][2].directions=6;
firstfloor[13][3].directions=15;
firstfloor[14][4].directions=6;
firstfloor[15][5].directions=6;
firstfloor[16][6].directions=7;
firstfloor[16][7].directions=7;
firstfloor[16][8].directions=7;
firstfloor[16][9].directions=7;
firstfloor[16][10].directions=8;
firstfloor[15][11].directions=8;
firstfloor[14][12].directions=8;
firstfloor[13][13].directions=16;
firstfloor[12][14].directions=8;
firstfloor[11][15].directions=8;
firstfloor[10][16].directions=1;
firstfloor[9][16].directions=1;
firstfloor[8][16].directions=1;
firstfloor[7][16].directions=1;
firstfloor[6][16].directions=2;
firstfloor[5][15].directions=2;
firstfloor[4][14].directions=2;
firstfloor[3][13].directions=17;
firstfloor[2][12].directions=2;
firstfloor[1][11].directions=2;
firstfloor[0][10].directions=3;
firstfloor[0][9].directions=3;
firstfloor[0][8].directions=13;
firstfloor[0][7].directions=3;
firstfloor[0][6].directions=4;
firstfloor[1][5].directions=4;
firstfloor[2][4].directions=4;
firstfloor[3][3].directions=18;
firstfloor[4][2].directions=4;
firstfloor[5][1].directions=4;
firstfloor[1][8].directions=5;
firstfloor[2][8].directions=5;
firstfloor[3][8].directions=5;
firstfloor[4][8].directions=19;
firstfloor[5][8].directions=5;
firstfloor[6][8].directions=5;
firstfloor[7][8].directions=5;
firstfloor[8][8].directions=14;
firstfloor[9][8].directions=5;
firstfloor[10][8].directions=5;
firstfloor[11][8].directions=5;
firstfloor[12][8].directions=19;
firstfloor[13][8].directions=5;
firstfloor[14][8].directions=5;
firstfloor[15][8].directions=5;
firstfloor[8][1].directions=7;
firstfloor[8][2].directions=7;
firstfloor[8][3].directions=7;
firstfloor[8][4].directions=20;
firstfloor[8][5].directions=7;
firstfloor[8][6].directions=7;
firstfloor[8][7].directions=7;
firstfloor[8][9].directions=7;
firstfloor[8][10].directions=7;
firstfloor[8][11].directions=7;
firstfloor[8][12].directions=20;
firstfloor[8][13].directions=7;
firstfloor[8][14].directions=7;
firstfloor[8][15].directions=7;
firstfloor[7][4].directions=11;
firstfloor[9][4].directions=11;
firstfloor[4][7].directions=12;
firstfloor[4][9].directions=12;
firstfloor[12][7].directions=12;
firstfloor[12][9].directions=12;
firstfloor[7][12].directions=11;
firstfloor[9][12].directions=11;
firstfloor[4][4].directions=2;
firstfloor[4][6].directions=7;
firstfloor[4][10].directions=3;
firstfloor[4][12].directions=8;
firstfloor[6][4].directions=5;
firstfloor[6][12].directions=5;
firstfloor[10][4].directions=1;
firstfloor[10][12].directions=1;
firstfloor[12][4].directions=4;
firstfloor[12][6].directions=7;
firstfloor[12][10].directions=3;
firstfloor[12][12].directions=6;
firstfloor[11][0].directions=0;
firstfloor[5][16].directions=0;
}
printbothfloors.c
#include <stdio.h>
#include <stdlib.h>
#include "motion.h"
void printbothfloors(){
// printf("printfloor is running");
int upper, lower, i, j;
printf("%4d %4d %4d %4d %4d", firstfloor[6][0].directions, firstfloor[7][0].directions, firstfloor[8][0].directions, firstfloor[9][0].directions, firstfloor[10][0].directions);
printf("%4d %4d %4d %4d %4d", firstfloor[6][16].directions, firstfloor[7][16].directions, firstfloor[8][16].directions, firstfloor[9][16].directions, firstfloor[10][16].directions);
printf("FIRST FLOOR");
printf("\n-");
/* The next for loop prints out the upper edge */
for (upper = 0; upper < 18; upper++){
printf("----");
}
printf("\n");
/*The next for loop prints out the floor, every element is 4 digits wide */
for (i = 0; i <= 16; i++){
printf("|");
for(j = 0; j <= 16; j++){
printf("%4d", firstfloor[i][j].directions);
}
printf(" |\n");
}
/* The next for loop prints out the lower edge */
for (lower = 0; lower < 18; lower++){
printf("----");
}
printf("-\n");
/*
printf("SECOND FLOOR");
// printf("printfloor is running");
printf("\n-----");
// The next for loop prints out the upper edge
for (upper = 0; upper < 17; upper++){
printf("----");
}
printf("\n");
//The next for loop prints out the floor, every element is 4 digits wide
for (i = 0; i <= 16; i++){
printf("|");
for(j = 0; j <= 16; j++){
printf("%4d", secondfloor[i][j].directions);
}
printf(" |\n");
}
// The next for loop prints out the lower edge
for (lower = 0; lower < 17; lower++){
printf("----");
}
printf("-----\n");
*/
}
prog2.c
#include <stdio.h>
#include <stdlib.h>
#include "motion.h"
//#include "printbothfloors.h"
int main(){
int row = 0;
int column = 0;
initializeArrays();
// printbothfloors();
/*
for (row=0; row < 17; row++){
for (column=0; column < 17; column++){
// firstfloor[row][column].directions=0;
// secondfloor[row][column].directions=5;
//firstfloor[i][j].isRobotHere=0;
//secondfloor[i][j].isRobotHere=0;
//firstfloor[i][j].isMultipleDirections=0;
//secondfloor[i][j].isMultipleDirections=0;
}
}
firstfloor[6][0].directions=5;
firstfloor[7][0].directions=5;
firstfloor[8][0].directions=14;
firstfloor[9][0].directions=5;
firstfloor[10][0].directions=6;
firstfloor[11][1].directions=6;
firstfloor[12][2].directions=6;
firstfloor[13][3].directions=15;
firstfloor[14][4].directions=6;
firstfloor[15][5].directions=6;
firstfloor[16][6].directions=7;
firstfloor[16][7].directions=7;
firstfloor[16][8].directions=7;
firstfloor[16][9].directions=7;
firstfloor[16][10].directions=8;
firstfloor[15][11].directions=8;
firstfloor[14][12].directions=8;
firstfloor[13][13].directions=16;
firstfloor[12][14].directions=8;
firstfloor[11][15].directions=8;
firstfloor[10][16].directions=1;
firstfloor[9][16].directions=1;
firstfloor[8][16].directions=1;
firstfloor[7][16].directions=1;
firstfloor[6][16].directions=2;
firstfloor[5][15].directions=2;
firstfloor[4][14].directions=2;
firstfloor[3][13].directions=17;
firstfloor[2][12].directions=2;
firstfloor[1][11].directions=2;
firstfloor[0][10].directions=3;
firstfloor[0][9].directions=3;
firstfloor[0][8].directions=13;
firstfloor[0][7].directions=3;
firstfloor[0][6].directions=4;
firstfloor[1][5].directions=4;
firstfloor[2][4].directions=4;
firstfloor[3][3].directions=18;
firstfloor[4][2].directions=4;
firstfloor[5][1].directions=4;
firstfloor[1][8].directions=5;
firstfloor[2][8].directions=5;
firstfloor[3][8].directions=5;
firstfloor[4][8].directions=19;
firstfloor[5][8].directions=5;
firstfloor[6][8].directions=5;
firstfloor[7][8].directions=5;
firstfloor[8][8].directions=14;
firstfloor[9][8].directions=5;
firstfloor[10][8].directions=5;
firstfloor[11][8].directions=5;
firstfloor[12][8].directions=19;
firstfloor[13][8].directions=5;
firstfloor[14][8].directions=5;
firstfloor[15][8].directions=5;
firstfloor[8][1].directions=7;
firstfloor[8][2].directions=7;
firstfloor[8][3].directions=7;
firstfloor[8][4].directions=20;
firstfloor[8][5].directions=7;
firstfloor[8][6].directions=7;
firstfloor[8][7].directions=7;
firstfloor[8][9].directions=7;
firstfloor[8][10].directions=7;
firstfloor[8][11].directions=7;
firstfloor[8][12].directions=20;
firstfloor[8][13].directions=7;
firstfloor[8][14].directions=7;
firstfloor[8][15].directions=7;
firstfloor[7][4].directions=11;
firstfloor[9][4].directions=11;
firstfloor[4][7].directions=12;
firstfloor[4][9].directions=12;
firstfloor[12][7].directions=12;
firstfloor[12][9].directions=12;
firstfloor[7][12].directions=11;
firstfloor[9][12].directions=11;
firstfloor[4][4].directions=2;
firstfloor[4][6].directions=7;
firstfloor[4][10].directions=3;
firstfloor[4][12].directions=8;
firstfloor[6][4].directions=5;
firstfloor[6][12].directions=5;
firstfloor[10][4].directions=1;
firstfloor[10][12].directions=1;
firstfloor[12][4].directions=4;
firstfloor[12][6].directions=7;
firstfloor[12][10].directions=3;
firstfloor[12][12].directions=6;
firstfloor[11][0].directions=0;
firstfloor[5][16].directions=0;
*/
// for (i = 0; i < 17; i++){
// firstfloor
// printbothfloors();
// pbf_entrypoints();
/*
row = 0;
column = 0;
while (i < 17){
firstfloor[i][8] = 1;
secondfloor[i][8] = 1;
firstfloor[8][i] = 1;
secondfloor[8][i] = 1;
i++;
}
*/
printf("Function got here");
printbothfloors();
return 0;
}
Valid indices for Type arr[N] are between 0 and N-1.
This goes for any Type and for any number of dimensions.
Indexes in C start at 0, so if you declare an array to have 16 elements, valid indexes start from 0 and end at 15.
16 boxes, numbered 0 to 15:
---------------------------------------------------------------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---------------------------------------------------------------------------------
Accessing an element outside of this range (e.g. by using the index -1 or 16) invokes undefined behaviour.
Both the first answers are correct, I'll add some examples from your code.
firstfloor[6][16].directions
firstfloor[x][y], has been initialized as firstfloor[16][16] meaning the values x and y can can from 0 to 15. The numbering system is 0 based, a hang-over from Java's C language ancestry. 0-15 covers 16 elements.
/*The next for loop prints out the floor, every element is 4 digits wide */
for (i = 0; i <= 16; i++){
printf("|");
for(j = 0; j <= 16; j++){
printf("%4d", firstfloor[i][j].directions);
}
printf(" |\n");
}
The two for loops, start correctly at i = 0 and should only continue while i < 16 or if you prefer i <= 15.
At the moment I'm personally jumping between Java, C and Python, so someone might correct me in this, but calling firstfloor[6][16] if it does not generate an array out-of-bounds error, will give you the same result as firstfloor[7][0]. This might explain why you are observing the first columns being confused with the last.
Good luck :-)

Resources