-3

I create and fill my 2d array of unsigned char in my struct using parser of a file that contains numbers separated by spaces

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


struct imagem{
    unsigned char ** matrix;
    char* file_path;
    int height;
    int width;
    int max_cinza;
    int histograma[256];
    char* location;
};

struct imagem* lerImagem(char file_path[])
{

    struct imagem* imagem = malloc(sizeof(struct imagem)); 
    imagem->file_path = file_path;
    FILE* ptr;
    ptr = fopen(file_path, "r");
    
    if (NULL == ptr) {
        printf("A imagem não está no file_path selecionado \n");
        imagem->height = 0;
        return imagem;
    }
    int MAX_LEN = 10000;
    char buf[] = "";

    fgets(buf, MAX_LEN, ptr); 
    char width[10], height[10];

    fscanf(ptr, "%s %s", width, height);

    int int_largura = atoi(width);
    int int_altura = atoi(height);
    imagem->height = int_altura;
    imagem->width = int_largura;


    imagem->matrix = (unsigned char**) malloc(imagem->height * sizeof(unsigned char*)); 
    for (int i = 0; i < int_altura; i++) {
        imagem->matrix[i] = (unsigned char*) malloc(imagem->width* sizeof(unsigned char)); 
    }
    

    
    fscanf(ptr, "%u", &imagem->max_cinza);

    for(int row = 0; row < imagem->height; row++){
        for(int column = 0; column < imagem->width; column++){
            fscanf(ptr, "%u ", &(imagem->matrix[row][column]));
            }
        }   

    fclose(ptr);

    return imagem;
}

void freeImagem(struct imagem* imagem_input){
    
    printf("iniciando free de matrix");
    
    for(int i=0; i < imagem_input->height; i++){
            free(imagem_input->matrix[i]);
    }
    free(imagem_input->matrix);
    
    free(imagem_input);
}

I can compile and run that without any errors. The program seems to work randomly, as sometimes it frees properly and another times the program just stops without any explanation.

  • 1
    [tag:C] - C is distinct from C++ and it should not be combined with the C++ tag without a specific reason. – 273K Jun 20 '23 at 21:53
  • Is this your actual code? Does this compile? This looks like it should not: `struct imagem imagem = malloc(sizeof(struct imagem));`. – pmacfarlane Jun 20 '23 at 21:54
  • `struct imagem imagem = malloc(sizeof(struct imagem))` -- Unless `imagem` is a `void *`, this is not C++ code. In C++, this will not compile without having to cast `malloc` to the pointer type (unless again, the type being assigned to is `void *`). – PaulMcKenzie Jun 20 '23 at 21:55
  • It was wrong, I fixed the tags – Vinicius Caetano Jun 20 '23 at 22:05
  • `struct imagem imagem = malloc(sizeof(struct imagem));` is not valid C. Please post your actual code, preferably as a [mre]. – pmacfarlane Jun 20 '23 at 22:09
  • @pmacfarlane Is not? I can compile that without any errors or warnings using gcc. – Vinicius Caetano Jun 20 '23 at 22:20
  • 3
    @ViniciusCaetano You realize that they questioned the code as it looked before you edited the question, right? It shouldn't come as a surprise since you change the very thing they questioned. Anyway, it's still not a [mre]. We can't run this to reproduce the problem. You may also want to add some compiler options: `-Wall -Wextra -pedantic-errors -g -fsanitize=address,undefined` are good. Compile with that, fix the warnings and then run the program and see if you get an error report of some kind. – Ted Lyngmo Jun 20 '23 at 22:24
  • `imagem->height` is used in `malloc()` and `int_altura` is used in the following loop. – 273K Jun 20 '23 at 22:58
  • @ViniciusCaetano also add a basic `main` function and an example input file, so that we can compile and run it locally and see the problem happening. – Leon Kacowicz Jun 20 '23 at 23:03

3 Answers3

1

These lines appear problematic:

    char buf[] = "";
    fgets(buf, MAX_LEN, ptr); 

buf should point to an array that is at least MAX_LEN long, since fgets might write up to MAX_LEN bytes read from ptr.

I suggest using malloc to allocate MAX_LEN bytes to buf, before calling fgets(buf, MAX_LEN, ptr)

edit: in the code you just read 10k bytes into buf, but you don't use buf anymore after that. Are you sure this is the intended behavior?

  • I think your observations are valid. I'm not sure they are an answer. Maybe better as comments (unless you are convinced this will fix the OP's problem). – pmacfarlane Jun 20 '23 at 23:12
  • @pmacfarlane I agree. I'm not sure this will fix the problem, as there might be other bugs besides this one. Besides that, the asker did not provide (yet) an example of a file for which this code is supposed to run correctly. edit: to be honest, I believe that fixing this will not fix the code, as reading (and throwing out) the first 10k bytes of the file appear to be a very weird behavior. I suspect that this couple of lines should just be deleted. – Leon Kacowicz Jun 20 '23 at 23:47
  • I use the fgets to skip a blank line in the beginning of the file that I am parsing. – Vinicius Caetano Jun 21 '23 at 10:29
  • @ViniciusCaetano `buf` is a `char[1]` so you have space for `1` `char`, but you tell `fgets` that it has room for `10000`. Keep in mind that the null terminator takes `1`, which leaves room for `0` characters. `fgets` will try to read a line, including `\n`, so `buf` would need to be at least a `char[2]` in order to read an empty line. When you try reading an empty line into a `char[1]` like you do now since you've lied and said there's room for `10000`, you'll cause undefined behavior. – Ted Lyngmo Jun 21 '23 at 15:23
  • @ViniciusCaetano, if the first line contain more characters than you allocated in buf, you will have a buffer overflow, which means that fgets will write to memory positions that are not contained by buf. This means that it can overwrite the value of other variables, or it can cause a segfault (if it tries to write to memory positions that are not allocated to your program). If your intention is to skip a line, you can refer to this: https://stackoverflow.com/questions/2799612/how-to-skip-a-line-when-fscanning-a-text-file – Leon Kacowicz Jun 21 '23 at 20:40
1

At least these problems:

Enable all warnings

These 4 lines all emit warnings with a well enabled compiler:

imagem->height * sizeof(unsigned char*));
imagem->width * sizeof(unsigned char));
fscanf(ptr, "%u", &imagem->max_cinza);
fscanf(ptr, "%u ", &(imagem->matrix[row][column]));

Incorrect format

"%u" matches a unsigned *, not unsigned char *.

struct imagem{
    unsigned char ** matrix;

    ...

    fscanf(ptr, "%u ", &(imagem->matrix[row][column]));  // Bad!

Better as

fscanf(ptr, "%hhu ", &(imagem->matrix[row][column]));  // Better

Drop unneeded " " and check result

if (fscanf(ptr, "%hhu", &(imagem->matrix[row][column])) != 1) {
  ; // Handle error
}  // Even better

Buffer too small

@Leon Kacowicz

Sample alternative:

// int MAX_LEN = 10000;
// char buf[] = "";
// fgets(buf, MAX_LEN, ptr); 
#define MAX_LEN 10000
char buf[10000];
if (fgets(buf, sizeof buf, ptr) == NULL) {
  ; // Handle input error
}

Use a C compiler

Comments suggest OP is using another language (C++) to compile C code.

Improve allocation

// imagem->matrix = (unsigned char**) malloc(imagem->height * sizeof(unsigned char*)); 

if (imagem->height < 0) {
  Handle_error(); // TBD code
}
imagem->matrix = malloc(sizeof imagem->matrix[0] * imagem->height); 
if (imagem->matrix == NULL && imagem->height) {
  Handle_error(); // TBD code
}

Never use "%s" without a width when scanning

char width[10], height[10];

// fscanf(ptr, "%s %s", width, height);
fscanf(ptr, "%9s %9s", width, height);

Better, scan into the int and check result.

int int_largura, int_altura;
if (fscanf(ptr, "%s %s", &int_largura, &int_altura) != 2) {
  Handle_error();
}

Mixing fscanf() and fgets() is tricky

This often fouls up learner code. Best to first use fgets()` only.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

In the end, the problem was in file_path and location attributes, as I didn't used malloc to use them, this leads my program to broke randomly.

  • Please bear in mind that the problem you just pointed out lies in a part of the program that *you did not include in the question*. Along with the numerous bugs the other commenters found in your code, this one you mentioned could be preventing your program from working, and it would be impossible for anyone to find out, since it's not included in the question. Next time you post a question, please include all relevant parts of the program, and an example input for which it should work. Please, help other people help you. – Leon Kacowicz Jun 24 '23 at 17:29
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 24 '23 at 21:04