Search code examples
cmemorystruct

array data is missing


When I run the below program, I do not understand why buf.data, is empty. At first I thought It may be my misunderstanding of memory, so I tried to malloc the buffer array, but it didn't change, the programs output.

#include <stdio.h>

typedef void Write(void *, char);

struct Writer {
  void *impl;
  Write *write;
};

void fprint(struct Writer *w, const char *s) {
  while (*s)
    w->write(w->impl, *s++);
}

struct StandardOut {
  FILE *f;
};

void StandardOut_write(struct StandardOut *w, char c) { fputc(c, w->f); }

struct Buffer {
  char *data;
  size_t size;
};

void Buffer_write(struct Buffer *b, char c) {
  if (b->size > 0) {
    *b->data++ = c;
    b->size--;
  }
}

int main() {
  struct Writer stdoutw = (struct Writer){
      .impl = &(struct StandardOut){stdout},
      .write = (Write *)StandardOut_write,
  };

  fprint(&stdoutw, "console meat\n");

  char data[1024];

  struct Writer bufw = (struct Writer){
      .impl = &(struct Buffer){.data = data, .size = sizeof(data)},
      .write = (Write *)Buffer_write,
  };

  fprint(&bufw, "buffered beefalo\n");

  struct Buffer buf = *(struct Buffer *)bufw.impl;
  fprint(&stdoutw, buf.data);

  fprint(&stdoutw, data[0] ? data : "buffer is empty");
}

This is the output of the program:

❯ zig cc interfaces.c
❯ ./a.out
console meat
buffered beefalo

So it is not printing the message in the buffer. Further the array is not empty from mains point of view. Because otherwise the ternary message should be printed, and we would not see the buffered message at all.

I dont know any c, so I dont know if this code is good or bad practice. Just messing around.


Here is a more simplified example outlining the same issue.

#include <stddef.h>
#include <stdio.h>

struct Buffer {
  char *data;
  size_t size;
  size_t offset;
};

void buf_write(struct Buffer *b, const char c) {
  if (b->size > 0) {
    *b->data++ = c;
    b->size--;
  }
}

void buf_print(struct Buffer *b, const char *s) {
  while (*s)
    buf_write(b, *s++);
}

int main() {
  char data[32];
  struct Buffer buf = {data, 32};

  buf_print(&buf, "Hello, world!\n");

  printf("buf.data = %s\n", buf.data);
  printf("data     = %s\n", data);
}

Why does the programs output not show buf.data?

# program output
buf.data = 
data     = Hello, world!

Solution

  • Buffer_write increments b->data. For b, it is passed the address of bufw.impl. So bufw.impl.data is incremented and no longer points to the beginning of the array data. buf is later set to be a copy of bufw.impl. So, when fprint(&stdoutw, buf.data); is executed, buf.data is pointing after the string that was copied into data. The memory there is uninitialized.