Почему выводит неполную информацию о файле изображения?

Тут странная ситуация с программой выходит: Если вводить текст вручную или подавать его из файла, то информация выводится как надо. Если же попытаться загрузить информацию из файла изображения xxx.jpg, то почему-то печатает только первые четыре байта, хотя информацию передаёт и записывает как следует. То есть на выходе получается тоже изображение.

Я думал, что он грешит на 00 в HEX данных изображения, но информацию передаёт нормально, только не выводит её почему-то...

Извиняюсь за польский, но думаю, что не критично.

Вот код:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

#define READ        0
#define WRITE       1
#define N 10000000

char string[N];
char hex[2*N];

void clear(char *tab, int par)
{
    int i;
    for(i = 0; i < par; i++)
    {
        tab[i] = 0;
    }
}

void clear_stdin()
{
    int c;
    while ((c = getchar()) != '\n' && c != EOF){
        continue;
    }
}

char plik_read(char* string, int par)
{
    FILE *file;
    char ADRES[256];
    printf("Wpisz adres pliku razem z formatem! \n");
    fflush(stdout);
    
    if (strchr(ADRES, '\n') == NULL) {
        clear_stdin();
    }
    
    if (fgets(ADRES, 256, stdin) == NULL) {
        /* Ma miejsce błąd lub został przeczytany EOF */
    }
    else {
        /* Usuwamy symbol końca wierza */
        size_t last = strlen(ADRES) - 1;

        if (ADRES[last] == '\n')
            ADRES[last] = '\0';

        /* Tutaj można przeanalizować wiersz */
    }
    printf("\n\n");
    if ((file = fopen(ADRES, "r+")) == NULL)
    {
        printf("Nie udalo sie otworzyc pliku, uruchom ponownie! \n");
        _exit(0);
    }
    else
    {
        int i = 0;
        while(!feof (file) && i<par) {
            if (fread(string , sizeof(char), par, file))
            {
                printf("%s", string);
                i += par;
            }
        }
        fclose(file);
    }
    return *string;
}

char plik_write(char* string, int par)
{
    int fp;
    fp = creat("file.dat", S_IREAD|S_IWRITE);
    if (fp == -1)
    {
        printf ("Nie moge utworzyc file.dat \n");
        _exit(0);
    }
    write (fp, string, par);
    close (fp);
    
    return *string;
}

int main()
{       
        if(fork() == 0)
        {
            char c='N';
            printf("Dane znajduja sie w pliku? Y/N? --> ");
            fflush(stdout);
            scanf ("%c", &c);
            printf("\n");

            if(c=='Y')
            {
                c='N';
                printf("To jest /dev/urandom ? Y/N? --> ");
                
                clear_stdin();
                    
                scanf ("%c", &c);
                if (c == 'Y')
                {                   
                    int U;
                    printf("Podaj liczbe odczytanych bajtow: ");
                    scanf ("%d", &U);
                    
                    plik_read(string, U);
                    printf("\n\n");
                    plik_write(string, U);
                    clear(string, U);
                }
                else
                {
                    plik_read(string, N);
                    printf("\n\n");
                    plik_write(string, N);
                    clear(string, N);
                }           
            }
            else
            {
                printf("Wpisz tekst: \n\n");
                fflush(stdout);
                
                if (strchr(string, '\n') == NULL) {
                clear_stdin();
                }
                
                fgets(string, N, stdin);
                printf("\n");
                plik_write(string, N);  
                clear(string, N);
                //~ for(int i=0; i<strlen(string); i++)
                //~ printf("%c", string[i]);    
            }
            
            /* tablica przechowujaca uchwyty na pliki odczytu i zapisu */
            int pdes[2];
            /* tworzymy pipe skladajaca sie z uchwytu do plikow do odczytu
            * i do zapisu (R i W); deskryptory zostana umieszczone w tablicy */
            pipe(pdes);
            
            if(fork() == 0)
                {
                    
                    FILE *fp;
                    
                    /* zamykamy niepotrzebny deskryptor */
                    close(pdes[READ]);

                        sleep(1);
                        fp = fopen("file.dat", "r+");           
                    
                            while(!feof (fp)) {
                                if (fread(string , sizeof(char), N, fp))
                                printf("%s \n", string);
                            }
                            fclose(fp);
                            
                            int len = strlen(string);

                              // Konwertowanie string to hex
                              
                              for (int i = 0, j = 0; i < len; ++i, j += 2)                            
                                sprintf(hex + j, "%02x", string[i] & 0xff);

                            printf("%s \nin hex is \n%s\n\n", string, hex);
                            
                            clear(string, N);

                        /* wysylamy podany ciag znakow przez pipe */
                        write(pdes[WRITE], hex, strlen(hex));

                }
                else
                {
                    if(fork()==0)
                    {
                        /* zamykamy niepotrzebny deskryptor */
                        close(pdes[WRITE]);

                            /* odbieramy cag znakow z pipe */
                            read(pdes[READ], hex, sizeof(hex));
                            
                            int len = strlen(hex);
                            
                            for (int i=0, j=1; i<len; j++)
                            {                               
                                fprintf(stderr, "%c%c ", hex[i], hex[i+1]);
                                    if(j==15)
                                    {
                                        fprintf(stderr, "\n");
                                        j = 0;
                                    }
                                i+=2;
                            }
                            clear(hex, 2*N);
                    }
                }
        }
        
    for(;;)
    pause();
        
    return 0;
}

Вот HEX данные изображения:

введите сюда описание изображения

Вот результат работы программы (изображение на выходе нормальное): введите сюда описание изображения


Ответы (1 шт):

Автор решения: KoVadim

Посмотрим на эти строки

int len = strlen(string);
// Konwertowanie string to hex
                          
for (int i = 0, j = 0; i < len; ++i, j += 2)                            
  sprintf(hex + j, "%02x", string[i] & 0xff);

printf("%s \nin hex is \n%s\n\n", string, hex);

В string хранится собственно массив с данными. strlen считает размер до первого нулевого символа (а он в этом массиве 5, если смотреть на картинку дампа). Поэтому, цикл и работает до 4. И выводит только 4 байта.

Давайте пофиксим минимальными жертвами. fread возвращает кол-во прочитанных "объектов", что в нашем случае равно количеству байт. sizeof(char) обычно равен 1 (в с++ с этим строго-строго, а вот о си я не знаю точных гарантий).

int len = fread(string , sizeof(char), N, fp)
fclose(fp);
// теперь len хранит реальный размер в байтах                        

// Konwertowanie string to hex
                          
for (int i = 0, j = 0; i < len; ++i, j += 2)                            
  sprintf(hex + j, "%02x", string[i] & 0xff);

printf("%s \nin hex is \n%s\n\n", string, hex);
                        
clear(string, N);

также там дальше используется strlen, где можно было бы размер и так посчитать

--- upd ---

как вывести весь файл в консоль в хекс виде

#include <stdio.h>

int main()
{
    FILE* f= fopen("/etc/hosts", "r");
    if (!f) {
        perror("no file");
        return -1;
    }
    char b[1];
    while(fread(b, sizeof(b), 1, f)) {
        printf("%02X ", b[0]);
    }
    fclose(f);
}

да, способ не очень эффективный, но для понимания подойдет. Лучше читать кусками по 4-8 килобайт.

→ Ссылка