4

At some memory allocation I find this. But I don't understand it.

char * mem_alloc()
{   
    char *point;
    char *a;
    point = (char *)malloc(block_num);

    a = *(char**) point;
    return a;
}   
chen youfu
  • 63
  • 6

6 Answers6

8

char * mem_alloc()

In my experience, functions returning a pointer are almost always a sign of flawed program design. Such a pointer could point at the following:

  • a local variable (blatant bug, UB)
  • a global/static (poor program design and also not thread-safe)
  • dynamic memory (poor program design, the code using the memory should handle the allocation, great potential for leaks)
  • or to one of the parameters passed to the function (poor program design, obscure function interface)

In this case, it points to dynamic memory, so we can likely assume poor program design and likely memory leaks to go with it.

point = (char *)malloc(block_num);

This code means that whoever wrote it is confused over how malloc works and how void pointers work. The result of malloc should never be typecasted, see this and this. The urge to typecast means that the programmer is confused about the C language, and/or that they are trying to compile C code on a C++ compiler.

"block_num" is suspicious, if this is a global, non-constant variable, then the program design is poor.

a = *(char**) point;

This means, take the address of point, which is pointing at uninitialized memory on the heap, then pretend that point is a pointer-to-pointer and thereby treat the garbage contents of the heap as if it was a pointer. Then return this pointer, pointing out at a random location in in la-la land, to the caller. And while doing so, create a memory leak.

Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396
0

This seems to set a to point's value(which is an address).
a = *(char**) point;
The above statement is typecasting point to - "pointer to a pointer" in `(char**) point' part. After this you have * for de-reference which changes it to
value of(pointer to a pointer)
=> pointer.
Thus the value(rather address) stored in point gets copied in a.
I am still not sure why this kind of code is written.

Manik Sidana
  • 2,005
  • 2
  • 18
  • 29
0

The code you posted is silly - are you sure it's complete?

"point" and "a" are both pointers.

"a" is initialized to "point" ... but "point" is completely uninitialized. Bad things will happen if the caller tries to use the return value "a".

Here's another example:

struct Point {
  int x;
  int y;
};

...

char * mem_alloc (int size)
{
  return (char *)malloc (size);
}

...
  Point *my_point = (Point *)mem_alloc (sizeof (struct Point));
  ...

This snippet is also silly ... but hopefully it illustrates a bit of what might be the rationale behind the code you're looking at...

paulsm4
  • 114,292
  • 17
  • 138
  • 190
0

a contains the value stored at the location pointed by point. Since point is uninitialized, it's pointing at a random location which contains random value and hence now a is pointing to random value which it was to begin with.

So the code is a no-op.

Chetan Narsude
  • 311
  • 1
  • 5
0

If you look at the concept of malloc, it always returns the base address of the allocated memory space,the actual syntax of the malloc function is Syntax:

pointer_to_store_base_add_of_mem = (data_type_of_allocated_memory)malloc(size_of_array)

In the above example you have allocated the character type of memory,hence you have used (char*) and in block_num you have given the size of the character array,and point pointer stores the base address of the allocated memory.

Nikson Kanti Paul
  • 3,394
  • 1
  • 35
  • 51
NappY
  • 1
0

Looking at the code chenyoufu123 posted in a comment on Lundin's answer:

ptr = (char *)malloc(block_num * size);
for(k=0; k<block_num-1; k++) {
    *((char **)(ptr + k*size)) = ptr + (k+1) * size;
}
*((char **)(ptr + k*size)) = NULL;

That is still bad code, but not completely senseless as the original code from the question. In particular together with the remark that it is used to create a linked list from another comment.

The situation is - assuming that the code is "correct" - that you have a

struct Node
{
    struct Node *next;
    /* More members */
};

and size_t size = sizeof(struct Node); (the names will be different, probably). Then

ptr = (char *)malloc(block_num * size);

allocates memory for block_num contiguous struct Nodes. One would usually allocate that as

struct Node *ptr = malloc(block_num * sizeof *ptr);

The loop

for(k=0; k<block_num-1; k++) {
    *((char **)(ptr + k*size)) = ptr + (k+1) * size;
}
*((char **)(ptr + k*size)) = NULL;

then reinterprets the address k * sizeof(struct Node) behind the start of the memory block, ptr + k*size, as a pointer to a pointer (a char**, but on most PC architectures nowadays, that's not important since all object pointers have the same representation - if it is important, the code is broken anyway) and writes the address of the next sizeof(struct Node) sized chunk of memory to that location. Since the next pointer is the first member of struct Node, that writes the address of the next struct Node in the list to the next pointer of the current struct Node. Finally, the next pointer of the last struct Node is set to NULL.

The usual way of writing this,

struct Node *ptr = malloc(block_num * sizeof *ptr);
int k;
for(k = 0; k < block_um - 1; ++k)
{
    ptr[k].next = &ptr[k+1]; // or ptr + (k+1), if you prefer
}
ptr[block_num-1].next = NULL;

is not only clearer, it also has the advantage of working on platforms where char* and struct Node* have different sizes or representations.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431