How to properly use pointers and structs in C?

  • Thread starter Thread starter frankfjf
  • Start date Start date
  • Tags Tags
    Pointers
Click For Summary

Discussion Overview

The discussion revolves around the proper use of pointers and structs in C, specifically in the context of implementing a ring buffer. Participants explore issues related to memory allocation, pointer assignment, and data integrity within the program.

Discussion Character

  • Technical explanation
  • Exploratory
  • Debate/contested

Main Points Raised

  • One participant describes experiencing odd output behavior when accessing struct members after initialization, suggesting potential issues with memory allocation or pointer usage.
  • Another participant points out that the main function allocates memory for the ring buffer and then calls rb_init, which also allocates memory, indicating that this double allocation may be unnecessary.
  • A suggestion is made to use the assignment *p = newrb; instead of p = &newrb; to correctly copy the contents of the struct rather than the pointer itself.
  • A participant reports that implementing the suggested fix appears to resolve the issue they were facing.
  • Another participant advises on the correct usage of memset to ensure the entire buffer is initialized to zero, rather than just the size of a pointer.
  • One participant acknowledges that they find pointers and memory management challenging in C programming.
  • A later reply elaborates on why p = &newrb; fails, explaining the distinction between stack and heap memory and the implications for data persistence after function exit.

Areas of Agreement / Disagreement

Participants generally agree on the issues related to memory management and pointer assignment, with some solutions proposed and accepted. However, the initial problem remains unresolved until the suggested changes are implemented and tested.

Contextual Notes

There are limitations regarding the understanding of memory allocation and the lifecycle of stack versus heap variables, which are critical to the discussion but not fully resolved.

frankfjf
Messages
166
Reaction score
0
Hello all,

I am experiencing some odd output behavior from a program that I am working on:

Header file

Code:
#include <pthread.h>

struct ringbuf_t
{
  pthread_mutex_t mutex;
  pthread_cond_t cond_full;
  pthread_cond_t cond_empty;
  int bufsiz;
  int front;
  int back;
  char* buf;
};

extern struct ringbuf_t* rb_init (int bufsiz);

extern void rb_finalize (struct ringbuf_t* rb);

extern int rb_size (struct ringbuf_t* rb);

extern int rb_is_full (struct ringbuf_t* rb);

extern int rb_is_empty (struct ringbuf_t* rb);

extern void rb_insert (struct ringbuf_t* rb, int c);

extern int rb_remove (struct ringbuf_t* rb);

First source file

Code:
#include "ringbuf.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>

struct ringbuf_t* rb_init(int bufsiz)
{
  int x;
  char *temp = malloc(sizeof(char) * bufsiz);
  memset(temp, '\0', sizeof(temp));

  //temp[bufsiz-2] = 'w';

  struct ringbuf_t newrb = { PTHREAD_MUTEX_INITIALIZER,
			     PTHREAD_COND_INITIALIZER,
			     PTHREAD_COND_INITIALIZER,
			     bufsiz, 0, bufsiz - 1, temp };

  struct ringbuf_t* p = malloc(sizeof(struct ringbuf_t));
  p = &newrb;

  return p;
}

void rb_finalize(struct ringbuf_t* rb)
{
  free(rb);
}

int rb_size(struct ringbuf_t* rb)
{
  int x;
  
  for (x = 0; rb->buf[x] != '\0'; x++)
    ;

  return x;
}

int rb_is_full(struct ringbuf_t* rb)
{
  if (rb->buf[rb->back] != '\0')
    return 1;

  return 0;
}

int rb_is_empty(struct ringbuf_t* rb)
{
  if (rb->buf[rb->front] != '\0')
    return 0;

  return 1;
}

Main source file
Code:
#include <stdio.h>
#include <stdlib.h>
#include "ringbuf.h"

int main()
{
  printf("\nTesting first method...");
  struct ringbuf_t *p = malloc(sizeof(struct ringbuf_t));
  p = rb_init(10);

  printf("\n%d", p->bufsiz);
  printf("\n%d", p->bufsiz);

  return 0;
}

I have been using the main method to test stuff out, and currently am experiencing some odd behavior, which I think may have to do with how I am allocating memory or using pointers, I am not sure. Basically, the first time I reference anything within the created struct (in this test I referenced bufsiz), it reports the correct value the first time, and then gives junk every time afterward. Same thing for function calls or a combination of both, as if the data is only available initially and then is immediately lost as soon as it gets accessed once.

Is there something off in my code that is causing this?

Thank you in advance.
 
Physics news on Phys.org
In main, you allocate a block of memory for a ring buffer, and then call rb_init, which also allocates a block of memory. You shouldn't need to do this twice.
 
Fair enough, but even implementing that fix causes the problem to persist.
 
Try:
*p = newrb;
instead of
p = &newrb;

That is, you need to copy the contents that is pointed to, and not the pointer itself.
 
Ooh, I think that fixed it! Thank you so much. Now hopefully I can actually get to the multi-threading part and actually get to the intended practice. :P
 
Just so you know, you should also use:
memset(temp, '\0', sizeof(char) * bufsiz);

instead of:
memset(temp, '\0', sizeof(temp));

Otherwise, you only set the first 4 bytes (which is the size of a pointer) of your buffer to zero .
 
Will do. Thanks. Playing around with pointers and memory seems to be my stumbling block in C.
 
I like Serena said:
Try:
*p = newrb;
instead of
p = &newrb;

That is, you need to copy the contents that is pointed to, and not the pointer itself.
In case it's not obvious why p = &newrb; isn't working for you, here's an explanation.

In main, p is set to the address of a ring buffer struct whose memory has been allocated from the heap. All is good.

In rb_init, a local variable named newrb is created. This struct is allocated on the stack. Just before rb_init exits, p is set to the address of newrb. Note that stack variables cease to exist outside the function in which they are declared. In practical terms, this means that whatever was at that location during the function's life can be used for other purposes after the function exits.

Back in main, p is pointing to a location on the stack that no longer holds what was stored in newrb.
 
Ah-ha. I figured it was something like that based on the behavior. Thank you Mark.
 

Similar threads

  • · Replies 2 ·
Replies
2
Views
3K
  • · Replies 1 ·
Replies
1
Views
11K
  • · Replies 17 ·
Replies
17
Views
2K
  • · Replies 3 ·
Replies
3
Views
1K
  • · Replies 2 ·
Replies
2
Views
6K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 12 ·
Replies
12
Views
9K
  • · Replies 7 ·
Replies
7
Views
2K