Ошибка сегментации при использовании sprintf и fwrite (); программа работает только с valgrind - PullRequest
0 голосов
/ 14 июля 2020

Я получаю ошибку сегментации при запуске моей программы, которая позволяет мне распечатать только одно поврежденное изображение. Однако, когда я запускаю программу с помощью valgrind, она распечатывает 49 из 50 фотографий, и единственная неработающая фотография - последняя.

После запуска help50 valgrind с программой я понял, что есть ошибка сегментации с sprintf, а также, возможно, что-то не так с fwrite () в конце программы. Приветствуются любые разъяснения.

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

int main(int argc, char *argv[])
{
    // Check you're actually recovering a file.
    if (argc != 2)
    {
        printf("Invalid entry.\n");
        return 0;
    }

    // Open file for reading.
    FILE *file = fopen(argv[1], "r");
    if (!file)
    {
        return 1;
    }

    // Set 1st photo as jpg.001.
    int counter = 1;

    // Check if bytes are jpg. signatures.
    for (int n = 0; counter < 51; n = n + 512)
    {
        // Sets an array to contain 4 values and directs pointer to start from nth value each time.
        unsigned char array[512];
        fseek(file, n, SEEK_SET);
        fread(array, 1, 512, file); // if EOF, won't have 512 to write into!!!

        // Declare character array jpg.
        char* jpg_name;

        // While 1st 4 bytes are jpg signature.
        if (array[0] == 0xff && array[1] == 0xd8 && array[2] == 0xff && (array[3] & 0xf0) == 0xe0)
        {
            // Convert integer to string and store into jpg character array. Increment image number.
            jpg_name = malloc(4*sizeof(char));
            sprintf(jpg_name, "%03i.jpg", counter);
            counter++;

            // Open images file to write into,allocate memory to jpg file to write into, write 512 bytes from array into image file.
            FILE *images = fopen(jpg_name, "a");
            fwrite(array, 1, 512, images);

            // Free file memory?
            free(jpg_name);
            fclose(images);
        }
        else // If 1st 4 bytes aren't jpg signature.
        {
            // Add bytes to existing image (if present), otherwise repeat loop.
            if (counter > 1)
            {
                FILE *images = fopen(jpg_name, "a");
                fwrite(array, 1, 512, images); // SEGMENTATION FAULT; need to detect end of file.
                fclose(images);
            }
            else
            {
                continue;
            }
        }
    }
}

1 Ответ

0 голосов
/ 14 июля 2020

предостережение: без вашего входного файла я не могу полностью протестировать этот предлагаемый код.

предостережение: предлагаемый код ожидает, что первая строка входного файла будет содержать «заголовок» для первого изображения .jpg

предостережение: предлагаемый код ожидает, что каждое изображение будет кратным 512 байтам

Следующий предлагаемый код:

  1. аккуратно компилирует
  2. выполняет желаемая функциональность (насколько это проверено)
  3. правильно проверяет ошибки ввода-вывода
  4. правильно открывает файлы в двоичном режиме (хотя Linux не заботится)
  5. предполагает что каждое изображение будет кратным 512 байтам
  6. правильно различает выходы из-за ошибки и успешные
  7. не включает файлы заголовков, это содержимое не используется

и теперь предлагаемый код:

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

int main(int argc, char *argv[])
{
    // Check the user entered a command line parameter for a input file name
    if (argc != 2)
    {
        fprintf( stderr, "USAGE: %s inputFileName\n", argv[0] );
        exit( EXIT_FAILURE );
    }

    // Open file for reading.
    FILE *file = fopen(argv[1], "rb");
    if (!file)
    {
        perror( "fopen for input file failed");
        exit( EXIT_FAILURE );
    }

    // Set 1st photo as jpg.001.
    // Declare character array jpg.
    char jpg_name[10];
    FILE *images = NULL;
    
    for (int counter = 0; counter < 51;  )
    {
        unsigned char array[512];
        ssize_t bytesRead;
        if( (bytesRead = fread(array, 1, 512, file) != 512 ) )
        {
            perror( "fread failed" );
            fclose( images );
            fclose( file );
            exit( EXIT_FAILURE );
        }

        // if 1st 4 bytes are jpg signature.
        if (    array[0] == 0xff 
            &&  array[1] == 0xd8 
            &&  array[2] == 0xff 
            && (array[3] & 0xf0) == 0xe0)
        {
            if( images )
            {
                fclose( images );
                images = NULL;
                counter++;
            }
            
            sprintf(jpg_name, "%03i.jpg", counter+1);

            images = fopen(jpg_name, "wb");
            if( ! images )
            {
                perror( "fopen for output file failed" );
                fclose( file );
                exit( EXIT_FAILURE );
            }
        }
        
        // Add bytes to current output image
        if( fwrite(array, 1, 512, images) != 512 )
        {
            perror( "fwrite failed" );
            fclose( images );
            fclose( file );
            exit( EXIT_FAILURE );
        }
    }
    
    fclose( images );
    fclose( file );
}
...