0
P2
5 7
255
100 114 111 100 112
90  110 112 110 111
90  110 124 110 119
80  110 110 110 118
90  110 100 110 109
111 110 163 110 120
100 98  111 145 112

I need to read this pgm file in C using fscanf

I have managed to read line one and store the P2 in a variable called p2 I'm stuck on reading (line 2 integer 1) and (line 2 integer 2) which are 5 & 7 I want to store read them and store them in variables row and col

Next I want to read in line 3 "255" and store that also

Them I need to read Everything from line 4 onward and store all the rest of the greyscale values in a variable greyscale.

I understand everything I need to read the file except reading each line and integer using fscanf can someone help here is my code so far

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    char p2[2];
    int row[3];
    int col[3];
    int max[4];
    int greyscale[35];
    int i;
    FILE *input_fptr;

    if ((input_fptr = fopen("image1.pgm", "r")) == NULL)
    {
        printf("ERROR! File cannot be opened.");

        exit(1);
    }

    // Read in Line 1  using fscanf
    fscanf(input_fptr, "%s", p2);
    printf("Line 1 data is: %s\n", p2);
    
    // Read in Line 2 rows and colulmns
    while ((fscanf (input_fptr, "%d", &row)) == 3)
    {
        printf("%d", row);
    }
    printf("\n");
    
    fclose(input_fptr);
    
    return 0;
    
}

  • 2
    It should be `char p2[3];`. You forgot to leave room for the null terminator. – Barmar Dec 10 '21 at 18:35
  • You only have one `%d` in the scanf string for the rows. If you want to read 3 numbers it should be `%d %d %d`. And then you need 3 more arguments for where to write the values -- it won't automatically spread the array. – Barmar Dec 10 '21 at 18:36
  • Why are `row` and `col` declared as arrays? – Barmar Dec 10 '21 at 18:37
  • Change them to ordinary integers, then `scanf("%d %d", &col, &row);` – Barmar Dec 10 '21 at 18:39
  • Not only was `char p2[2]` too small to read `"P2"` as a nul-terminated string, if the file was the wrong data type (and it's part of the role of the header to identify the data type) then you *still* risk breaking the array with `char p2[3]`. – Weather Vane Dec 10 '21 at 18:45

1 Answers1

0

A string in C is a null-terminated character array. That is, a series of non-null characters followed by a null character.

"P2" in memory would be { 'P', '2', '\0' }. char [2] could only hold the first two bytes here. You must make sure to have enough room to store this terminating byte, or risk running outside of memory boundaries when using functions that expect to work in terms of C strings.

On the other hand, the format specifier "%s" will read as many characters as it can until it reaches a whitespace character (isspace), which may lead to buffer overflows. For this reason, it is a good idea to limit the maximum amount of data read with a field-width specifier. This should be the size of your array minus one, as *scanf will always need room to place the null-terminating byte.

char string[3];
scanf("%2s", string);

row, col and max should not be be arrays. They are each a singular value.

The dimensions of greyscale would appear to relate to the values of col and row. As such, it would be more appropriate to size this array at runtime using a variable-length array, or dynamic memory allocation.

You will want to use the values of col and row as maximums to loop through and populate your array.


Here is an example using a two dimensional variable-length array. Use rows * cols as the size for a one dimensional array.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    FILE *file;
    char title[16];
    size_t cols, rows;
    unsigned max;

    if (argc < 2 || NULL == (file = fopen(argv[1], "r")))
        /* handle file failure */;

    if (4 != fscanf(file, "%15s%zu%zu%u", title, &cols, &rows, &max))
        /* handle format failure */;

    unsigned data[rows][cols];

    for (size_t i = 0; i < rows; i++)
        for (size_t j = 0; j < cols; j++)
            if (1 != fscanf(file, "%u", &data[i][j]))
                /* handle format failure */;

    printf("%s [%zux%zu] (<=%u):\n", title, rows, cols, max);

    for (size_t i = 0; i < rows; i++) {
        for (size_t j = 0; j < cols; j++)
            printf("%3u ", data[i][j]);

        putchar('\n');
    }

    fclose(file);
}

./read-pgm image1.pgm output:

P2 [7x5] (<=255):
100 114 111 100 112 
 90 110 112 110 111 
 90 110 124 110 119 
 80 110 110 110 118 
 90 110 100 110 109 
111 110 163 110 120 
100  98 111 145 112 
Oka
  • 23,367
  • 6
  • 42
  • 53