confusion about printf() in C

Viewed 105

I'm trying to hexdump a file with following code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define SIZE 16

void pre_process(char buffer[],int len);

int main(int argc, char **argv){
    if(argc == 2){
        char *file = argv[1];
        FILE *input = fopen(file,"r");
        char buffer[SIZE];
        char *tmp = malloc(4);
        while(!feof(input)){ 
            printf("%06X  ",ftell(input)); /*print file pos*/
            fread(buffer,1,SIZE,input); /*read 16 bytes with buffer*/
           
            for (int i=0;i<SIZE;i += 4){ /*print each 4 bytes with hex in buffer*/
                memcpy(tmp,buffer+i,4);
                printf("%08X  ",tmp);
            }
            printf("*");
            pre_process(buffer,SIZE); /*print origin plain-text in buffer. subsitute unprint char with '*' */
            printf("%s",buffer);
            printf("*\n");
        }
        free(tmp);
        fclose(input);
   }
}

void pre_process(char buffer[],int len){
    for (int i=0;i<len;i++){
        if(isblank(buffer[i]) || !isprint(buffer[i]))
            buffer[i] = '*';
    }
}

reading a slice from lord of ring,result as below: enter image description here

so, why the hex code are all the same ? It looks like something wrong with printf("%08X ",tmp); thx for your help.

2 Answers

The answer lies here:

memcpy(tmp,buffer+i,4);
printf("%08X  ",tmp);

memcpy as you might already be aware, copies 4 bytes from buffer+i to where tmp is pointing to.

Even though this is done in a loop, tmp continues to hold the address of a specific location, which is never changed. The contents at that address/location in memory are updated with every memcpy() call.

In a nutshell, the house remains there only, hence the address remains the same but people change places, new people arrive as older ones are wiped out!

Also, there is plenty to improve/fix here. I recommend starting with enabling warnings by -Wall option with your compiler.

tmp stores the address of a buffer; that address never changes. What you want to print is the contents of the buffer that tmp points to. In this case, tmp point to a buffer of 4 chars; if you write

printf( "%08X ", *tmp );

you’ll only print the value of the first element - since tmp has type char *, the expression *tmp has type char and is equivalent to writing tmp[0].

To treat what’s in those bytes as an unsigned int (which is what the %X conversion specifier expects), you need to cast the pointer to the correct type before dereferencing it:

printf( "%08X ", *(unsigned int *) tmp );

We first have to cast tmp from char * to unsigned int *, then dereference the result to get the unsigned int equivalent of those four bytes.

This assumes sizeof (unsigned int) == 4 on your system - to be safe, you should write your malloc call as

char *tmp = malloc( sizeof (unsigned int) );

and

for ( int i = 0; i < SIZE; i += sizeof (unsigned int) )
{
  memcpy( tmp, buffer + i, sizeof (unsigned int) );
  ...
}

instead.

You should not use feof as your loop condition - it won’t return true until after you try to read past the end of the file, so your loop will execute once too often. You’ll want to look at the return value of fread to determine whether you’ve reached the end of the file.

Related