C - memory management - c

I just wrote some C code:
#include <stdlib.h>
#include <time.h>
#include <string.h>
typedef struct {
void **data;
time_t lastModified;
} container;
container *container_init() {
container *c = malloc(sizeof(container));
void *data = NULL;
c->data = &data;
c->lastModified = time(NULL);
return c;
}
void *container_getData(container *c) {
void **containerData = c->data;
return *containerData;
}
// only pass manually allocated data that can be free()'d!
void container_setData(container *c, void *data) {
free(container_getData(c));
c->data = &data;
}
void container_free(container *c) {
free(container_getData(c)); // <--- THIS LINE
free(c);
}
int main(int argc, const char *argv[]) {
for (int i = 0; i < 100000000; i++) {
char *data = strdup("Hi, I don't understand pointers!");
container *c = container_init();
container_setData(c, data);
container_free(c);
}
}
My logic was the following: When I call container_setData(), the old data is free()'d and a pointer to the new data is stored. That new data will have to be released at some point. That happens for the last time during the call to container_free().
I have marked a line in the container_free() function. I would have sworn I'd need that line in order to prevent a memory leak. However, I can't use the line ("object beeing freed was not allocated") and there's no memory leak if I delete it. How does the string from my loop ever get released?!
Could someone explain where the error is?

c->data = &data;
stores the address of the pointer data (the argument to your function), not the actual pointer. I.e., you're storing a pointer to a temporary.
You could have built the container structure with just a void *data member.

To explain larsmans answer with code make these changes:
typedef struct {
void *data;
time_t lastModified;
} container;
void *container_getData(container *c) {
return c->data;
}
void container_setData(container *c, void *data) {
free(c->data);
c->data = data;
}
void container_free(container *c) {
free(c->data);
free(c);
}
And other changes too -- this just gets you on the right track.

Related

Creating pointer to a typedef stack

I am not able to initialize all three pointers to struct S, and I don't know why.
I am using a fixed-length array as stack to store values.
The header file is created this way to hide information (struct S), and should be kept as generic as possible.
main.c
// main.c
#include <stdio.h>
#include "stack_exercise4.h"
int main(void) {
Stack *stack_1, *stack_2, *stack_3;
int a, b;
make_empty(stack_1);
make_empty(stack_2);
make_empty(stack_3);
return 0;
}
Problem is, after Stack *stack_1, *stack_2, *stack_3, only stack_2 has a valid address for Struct stack. stack_1 and stack_3 have some strange looking addresses, and I can't assign any values to stack_1->top, nor stack_3->top. What is the problem?
header file
// stack_exercise4.h
#ifndef STACK_EXERCISE4_H
#define STACK_EXERCISE4_H
#include <stdbool.h> /* C99 only */
typedef struct S Stack; /* incomplete type to hide the content
of S. */
void make_empty(Stack *s);
bool is_empty(const Stack *s);
bool is_full(const Stack *s);
void push(Stack *s, int i);
int pop(Stack *s);
#endif
stack source file
// stack_exercise4a.c
#include "stack_exercise4.h"
#include <stdio.h>
#define MAX_STACK_SIZE (10)
struct S {
int top;
int contents[MAX_STACK_SIZE];
};
void make_empty(Stack *s) {
s->top = 0;
}
bool is_empty(const Stack *s) {
return (s->top <= 0);
}
bool is_full(const Stack *s) {
return (s->top >= MAX_STACK_SIZE - 1);
}
void push(Stack *s, int i) {
if (!is_full(s)){
(s->contents)[s->top++] = i;
} else {
printf("Failed to push, Stack is full.\n");
}
}
int pop(Stack *s) {
return (s->contents)[s->top--];
}
The stack pointers must point on memory spaces before being dereferenced in make_empty(). Something like this could be the starting point: make_empty() allocates the memory space.
void make_empty(Stack **s) {
(*s) = (struct S *)malloc(sizeof(struct S));
(*s)->top = 0;
}
And so the initialization of the pointers would be:
make_empty(&stack_1);
make_empty(&stack_2);
make_empty(&stack_3);
Declare stack_X on stack instead.
#include <stdio.h>
#include "stack_exercise4.h"
int main(void) {
Stack stack_1 = {0}, stack_2 = {0}, stack_3 = {0};
int a, b;
make_empty(&stack_1);
make_empty(&stack_2);
make_empty(&stack_3);
return 0;
}
Otherwise, I't would need to have constructor/destructor for your Stack data structure e.g new_stack(Stack *ptr) del_stack(Stack *ptr). For beginner, I would recommend to use stack instead of heap (stay away from malloc).

Unwanted pointers modification

Situation: I'm currently working with chained lists and I am adding new elements through a function called inputRegistering(). I am positive that at the end of this function, an element have been added to the correct place.
Issue1: The added element modifies all the other to take its value.
Issue2: When exiting the function, and calling the inputReadingAll() function (which displays the list in its entirety), the elements are now all "empty", or replaced with gibberish (as can do the pointers).
Test1: I have tested to do a manual adding in the main() function and it seems everything worked fine. I can't understand what is the fundamental difference with my code though...
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 256
typedef struct
{
struct elt *first;
struct elt *last;
} Tfile;
typedef struct elt
{
char *val;
struct elt *next;
} Telt;
int fileAdd(Tfile *, char *);
void fileInit(Tfile *);
void inputReadingAll(Tfile *);
void inputRegistering(Tfile *);
int main(int argc, char **argv){
Tfile file;
fileInit(&file);
inputRegistering(&file);
inputRegistering(&file);
inputReadingAll(&file);
}
int fileAdd(Tfile *F, char *newVal){
Telt *newElt;
newElt = (Telt*)malloc(sizeof(Telt));
if(newElt == NULL){
printf("Error\n");
return 0;
}
newElt->val = newVal;
newElt->next = NULL;
if(fileTaille(F) == 0)
F->first = newElt;
else
F->last->next= newElt;
F->last = newElt;
return 1;
}
void fileInit(Tfile *F){
F->first = NULL;
F->last = NULL;
}
void inputReadingAll(Tfile *file){
printf("> Reading all function\nBEGIN\n");
Telt *currElt = file->first;
while(currElt != NULL){
printf("%p, %s\n", currElt, currElt->val);
currElt = currElt->next;
}
printf("END\n");
}
void inputRegistering(Tfile *file){
printf("> Registering function\n> What to register : \n> ");
char temp[MAXLEN];
fgets(temp, MAXLEN, stdin);
temp[strcspn(temp, "\n")] = 0;
printf("Registering %s\n", temp);
fileAdd(file, temp);
}
The (pointer to) local array temp of the function inputRegistering() is passed to the function fileAdd() and the pointer is directly stored to the structure.
This is bad because the array is local and it is invalidated on returning from the function inputRegistering().
Instead of this, the function fileAdd() should copy the passed string and store the pointer to the copy in the structure.
This can be done like this:
newElt->val = malloc(strlen(newVal) + 1); /* +1 for terminating null-character */
if (newElt->val == NULL) {
printf("Error\n");
free(newElt);
return 0;
}
strcpy(newElt->val, newVal);
instead of this:
newElt->val = newVal;

Dynamic stack assing value to a struct inside the stack struct

I'm having a problem in line: novo->conta.nome_cliente = valor2;. In this dynamic stack structure. Empilhar is a function to push a new element to the stack. Why i cant assign a new value to the structure inside the stack?
struct conta_de_luz
{
int cod_cliente;
char nome_cliente[40];
};
typedef struct Item {
struct conta_de_luz conta;
struct Item *anterior;
} Elemento;
void Inicializar(Elemento **topo) {
*topo = NULL;
}
int EstaVazia(Elemento **topo) {
if(*topo == NULL)
return VERD;
else
return FALSO;
}
void Empilhar(Elemento **topo, int valor, char valor2) {
Elemento *novo;
novo = (Elemento *) malloc(sizeof(Elemento));
novo->conta.cod_cliente = valor;
novo->conta.nome_cliente = valor2;
novo->anterior = *topo;
*topo = novo;
}
The problem is that line novo->conta.nome_cliente = valor2; assigns a char to something that is a string defined as char nome_cliente[40];.
So your function probably should have been void Empilhar(Elemento **topo, int valor, char* valor2). But that would still assume the value of valor2 remains in memory for the lifetime of topo.
Better would be void Empilhar(Elemento **topo, int valor, const char* valor2) and then use strcpy(novo->conta.nome_cliente, valor2);.
But this assumes valor2 including its NULL-terminator always fits within 40 characters. If this assumption is not guaranteed it's better to duplicate the string using strdup(). You will then also need to free() this seperately this in your cleanup function.

How to allocate a dynamic array of struct

i have a problem with the allocation of a dynamic struct array.
The struct is composed of a char* field, that is another dynamic array of char. After i allocate all arrays, windows block the program when i try to modifty a struct content. Code:
typedef struct
{
char *cod;
}code;
void create_cod(code *singleCode,int codeLength);
void create_codes(code *codes, int codesNumber, int codeLength);
int main()
{
int codesNumber=4, codeLength=10;
code *codes;
create_codes(codes, codesNumber, codeLength);
codes->cod = "abcd"; /*Windows block the program here*/
}
void create_cod(code *singleCode,int codeLength)
{
singleCode->cod = (char*)malloc(codeLength*sizeof(char));
return;
}
void create_codes(code *codes, int codesNumber, int codeLength)
{
codes= (code*)malloc(codesNumber*sizeof(code));
int i=0;
while(i<codesNumber)
{
create_cod(codes+i,codeLength);
i++;
}
return;
}

Heap corruption upon free( )

I've been getting heap corruption error when calling the free() function. The project worked in VC++ 2010. The whole building process is working ok, but in run-time I get the error: (CircularQueue is name of my project)
ERRORS:
Windows has triggered a breakpoint in CircularQueue.exe.
This may be due to a corruption of the heap, which indicates a bug in
CircularQueue.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while CircularQueue.exe
has focus.
The output window may have more diagnostic information.
#include "stdafx.h"
#include<stdio.h>
#include <string.h>
#include <Windows.h>
#include "CircularQ.h"
#define max 4
//char circQ[10][3145728];
Image_details_t circQ[max],*ptr[max];
Image_details_t *temp;
LONG q[10],front=0,rear=-1;
#if 1
void main()
{
int ch;
//void insert();
insert("h",1,1,1,1);
insert("h",1,1,1,1);
insert("h",1,1,1,1);
delet();
delet();
delet();
delet();
while(1);
}
#endif
void insert(char *img,int channel,int imgWidth,int imgHeight,int imgLen)
{
//int x;
//char x[20];
int l = 0;
if((front==0&&rear==max-1)||(front>0&&rear==front-1))
printf("Queue is overflow\n");
else
{
l = strlen(img);
//scanf("%d",&x);
if(rear==max-1&&front>0)
{
printf("hello i m here");
InterlockedCompareExchange( &rear,0,rear);
circQ[rear].img = (char *) malloc(1);
strcpy(circQ[rear].img,img);
circQ[rear].channel = channel;
circQ[rear].imgWidth = imgWidth;
circQ[rear].imgHeight = imgHeight;
circQ[rear].imgLen = imgLen;
//q[rear]=x;
}
else
{
if((front==0&&rear==-1)||(rear!=front-1))
{
InterlockedExchangeAdd(&rear,1);
circQ[rear].img = (char *)malloc(l);
strcpy(circQ[rear].img,img);
circQ[rear].channel = channel;
circQ[rear].imgWidth = imgWidth;
circQ[rear].imgHeight = imgHeight;
circQ[rear].imgLen = imgLen;
//q[rear]=x;
}
}
}
}
void delet()
{
char a[20];
// char *temp;
if((front==0)&&(rear==-1))
{
printf("Queue is underflow\n");
return;
//exit(0);
}
if(front==rear)
{
//a=q[front];
strcpy(a,circQ[front].img);
//temp = circQ[front];
//free(temp);
//free(circQ[rear].img);
InterlockedCompareExchange( &rear,-1,rear);
InterlockedCompareExchange( &front,0,front);
}
else
if(front==max-1)
{
//a=q[front];
strcpy(a,circQ[front].img);
//free(circQ[rear].img);
//temp = circQ[front];
//free(temp);
InterlockedCompareExchange( &front,0,front);
}
else
{
strcpy(a,circQ[front].img);
//free(circQ[rear].img);
temp = &circQ[front];
free(temp); // in this part problem is occurring
InterlockedExchangeAdd(&front,1);
//a=q[front];
}
printf("Deleted element is:%s\n",a);
free(&circQ[front]);
}
Header file:
#include <stdio.h>
#include <malloc.h>
#include <stdint.h>
typedef struct Image_details
{
char *img;
int channel;
int imgWidth;
int imgHeight;
int imgLen;
}Image_details_t;
void insert(char *img,int channel,int imgWidth,int imgHeight,int imgLen);
void delet();
You are freeing a non-heap variable, you shouldn't, remove this
free(&circQ[front]);
You allocate space for img member, just one byte, an empty string requires one byte for the terminating '\0', you then do strcpy() which is meant for strings, i.e. non-nul sequence of bytes followed by a nul, byte.
Maybe you mean
memcpy(circQ[rear].img, img, 1);
which is also the same as
circQ[rear].img[0] = img[0];
You should check the return value of malloc().
You don't need to cast the return value of malloc(), if you need to then you are using either the wrong compiler, or the wrong programming language.

Resources