2

I am very new to C and I have written a relatively simple code for an assignment that is supposed to take input from a file byte by byte and print a table of the hex values for the file similarly to the -od command. I moved all the code to a single file included here.

#include <stdio.h>
#include "dataDump.h"

//
// Created by crsan on 3/23/2023.
//
#include "dataDump.h"
int dataDump(char *fileName) {
    FILE *inFile = fopen(fileName, "r");
    if (inFile == NULL) {
        return -1;
    }
    int whiteSpace = 00000000;
    int line = 0;
    unsigned char c;

    printf("00000000");
    char *hex = NULL;
    for (int i = 0; (c = getc(inFile)) != EOF; i++) {
        sprintf(hex, "%02x", c);
        printf(" %s", hex);
        whiteSpace++;
        line++;
        if (line == 15) {
            printf("\n%08d", whiteSpace);
            line = 0;
        }

    }
    if (line != 0) {
        printf("\n%d", whiteSpace);
    }
    return whiteSpace;
}
int main(int argc, char *argv[]) {
    printf("test words");
    dataDump(argv[1]);
    return 0;
} 

however, before even the print statement from the main function there is a segmentation error and the code fails to compile farther.

This is supposed to be compiled using UNIX command line input, which I am unfamiliar with and could be the cause of the error. Aside from that, google told me that it was probably a memory allocation error, which I have yet to learn about. Other possibility I was thinking could be the sprintf I use to change to hex. If anyone has encountered this before or has any idea what the cause might be any assistance would be greatly appreciated.

Chris
  • 26,361
  • 5
  • 21
  • 42
  • You have included "dataDump.h" twice in your file, causing duplicate declaration of identifiers. Have you looked at the compiler diagnostics after compiling the program? – Jim Rogers Mar 24 '23 at 21:12
  • 3
    "before the printf" - not quite, stdout is line oriented, text will show up only after a newline, add newlines to the printouts to see where it got. Or step through the code using a debugger. – teapot418 Mar 24 '23 at 21:14
  • 2
    At a casual reading the best chance to crash is `sprintf(NULL,...)`. – teapot418 Mar 24 '23 at 21:16
  • 1
    In `main` you may also wish to ensure that `argc` is `2` or greater, otherwise `argv[1]` may cause issues. – Chris Mar 24 '23 at 21:19
  • 1
    `getc()` returns an `int`, not an `unsigned char`. You may have trouble detecting EOF without fixing that. – pmacfarlane Mar 24 '23 at 22:33
  • pluse-uno for some code and some thought/research about your problem. Good formatting too! Keep posting. – shellter Mar 24 '23 at 22:43
  • 1
    As @teapot418 says, "before the printf" is not quite true. But, it is *not* correct to say that "stdout is line oriented". stdout is often line buffered, but this comment suggests that stdout is always associated with a tty, and that is one of the biggest and most common blunders that beginners make. It may seem like a nit, but this is an important point to internalize early. If you add newlines to your printf statements but do not `fflush`, the behavior may be different when you run the program when stdout is not associated with a tty. – William Pursell Mar 25 '23 at 14:11

3 Answers3

2

The most likely cause of your error is trying to use sprintf to print into a NULL buffer.

   char *hex = NULL;
   for (int i = 0; (c = getc(inFile)) != EOF; i++) {
       sprintf(hex, "%02x", c);
       printf(" %s", hex);

The memory for this buffer is not allocated by sprintf. You'll want to leave space for a null terminator, so you could specify a char array with room for 8 char values, which would easily handle the value you want to hold:

    char hex[8];
    for (int i = 0; (c = getc(inFile)) != EOF; i++) {
        sprintf(hex, "%02x", c);
        printf(" %s", hex);

As noted in a comment, the construction of a string representation of the value, and then printing that string to standard output is unnecessary.

    for (int i = 0; (c = getc(inFile)) != EOF; i++) {
        printf(" %02x", c);
Chris
  • 26,361
  • 5
  • 21
  • 42
1

This demonstrates one way to accomplish what you need. It doesn't cover all the things you were coding but covers the basics of your defined goals. Hopefully it will help be enough to answer your questions. Best of luck.

#include <stdio.h>

int main()
{
    char value; // used to read the data one character (char is 1 byte) at a time.

    // create a file named test.txt & save some data in it.
    FILE * outFile; // define a pointer to File named outFile
    outFile = fopen("test.txt", "w"); // create a file named test.txt, open it in write mode.
    
    fprintf(outFile, "abcdefghivklmnopqrstuvwxyz1234567890\r\n"); // send some data to the file
    
    fclose(outFile); // close the file

    // open test.txt in read mode, read the data one char (byte) at a time & print it out.
    FILE * inFile; // define a pointer to File named inFile
    inFile = fopen("test.txt", "r"); // open a file named test.txt in read mode.
    
    while(1) // create a non-ending loop. we'll break out of it when we're finished reading the file.
    {
        value = fgetc(inFile); // get char from test.txt one byte at a time 
    
        if(feof(inFile)) // break the loop when we areat the end of the file.
            break;
    
        printf("%02x ",value); // print each char as hex
    }
    fclose(inFile); // colse inFile

    printf("\n"); // put a line break at the end of the printed data.

    return 0;
}
Chief Cook
  • 61
  • 5
1

You are almost certainly not getting the segmentation fault "before any part of [the] main function runs". The segmentation fault occurs later, but because of buffering you do not see any output from printf. printf does not always write data to the output stream. Instead, printf stores data in an internal buffer and only writes that data occasionally. The details of when writes can happen are not particularly important for this question, but the reasons should be understood. Writing data can be expensive, so the standard library implementations defer the write until enough data is available to make it worthwhile. There are 3 standard buffering modes: fully buffered (aka block buffered), line buffered, and unbuffered. If the stream is unbuffered, printf will always write data. If the stream is line buffered, printf will write data whenever a complete line is added to the buffer. With block buffering, printf will defer writes until a complete block (eg 4096 bytes) is available. You can always trigger a write by calling fflush on the stream. So if you want to ensure that you see the text, you can do:

printf("test words");
fflush(stdout);
  

Typically, the buffer is flushed when the program exits, but that does not always happen if the program terminates abnormally. A segmentation fault causes abnormal termination, and the buffer is not flushed.

Note that if the stream in line buffered, you can probably get away with printf("test words\n") or puts("test words") instead of calling fflush explicitly. One commenter suggests that this is adequate since "stdout is line oriented", but this is simply not always true. It is often true that stdout is line buffered, but not always. The explicit fflush is wise if you want to be sure the data is written.

William Pursell
  • 204,365
  • 48
  • 270
  • 300