Hello guys,
Can someone explain what is going on on this code?
1. why we needed **p in the function AllocString?
2. why if I change AllocString(strlen(s), &copy); to AllocString(strlen(s)-7, &copy); I can still get a good result?

Thanks!

#include <stdlib.h>

int main() {
    char *s="example";
    char *copy=NULL;
    AllocString(strlen(s), &copy);
    strcpy(copy, s);
    printf("%s\n", copy);
    free(copy);
}

int AllocString(int len, char **p) {
    char *str=malloc(len+1);
    if(str==NULL)
        return 0;
    *p=str;
    return 1;
}

Dani AI

Generated

Brief recap and practical next steps (building on and ):

  • The pointer-to-pointer pattern in the thread lets a function put a heap address into the caller's pointer; that is why the function receives a char **.
  • The observation that reducing the requested size "still works" is a symptom of memory corruption that happens not to crash immediately. It is not reliable and must be treated as a bug.

Concrete advice to avoid and diagnose the issue

  • Use the right integer types and avoid signed/unsigned surprises. Prefer size_t for sizes and lengths; subtracting constants from strlen() can lead to underflow if you mix signed and unsigned types.
  • Prefer simple, clear allocation APIs that return the pointer instead of a pointer-to-pointer. Example pattern:
char *alloc_string(size_t len) {
    char *p = malloc(len + 1);
    if (!p) return NULL;
    return p;
}

size_t n = strlen(s);
char *copy = alloc_string(n);
if (copy) memcpy(copy, s, n + 1);
  • For one-line copies prefer strdup or strndup where available. Always check the return value before using the pointer and call free() exactly once; set the pointer to NULL after freeing to avoid dangling pointers.

How to prove the bug and harden code

  • Use runtime tools to catch overruns: AddressSanitizer (-fsanitize=address) and Valgrind’s memcheck will flag writes past allocated buffers. See AddressSanitizer docs and Valgrind manual for quick usage.
  • Remember that a non-crashing overwrite can still corrupt allocator metadata or adjacent data; such bugs are intermittent and may appear later or only on different platforms/builds.

References: undefined behavior background and debugging tools — see and AddressSanitizer documentation.

Recommended Answers

All 5 Replies

>>1. why we needed **p in the function AllocString?

The function is receiving an address of a pointer. What is a pointer? It holds the address of a variable.

So,

say you have

int i;
int *ptr = &i; /* Pointer to an integer */
int **ptr1 = &ptr; /* Pointer to a pointer */

Now, this is the same in the function. You are passing the address of a pointer. So, you need a pointer to hold or recieve the address, and what type is it? It is a pointer to a pointer variable.

Hence the **.


i did not quite get the second question. Why would you want to allocate less number of bytes?

Thanks myk45 for your help.

Now, about the second question.. I don't want to allocate less of bytes, but lets say I did that.. why it won't return a segmentation fault?
I just want to understand what is going on if I allocate less bytes..

Thanks myk45 for your help.

Now, about the second question.. I don't want to allocate less of bytes, but lets say I did that.. why it won't return a segmentation fault?
I just want to understand what is going on if I allocate less bytes..

It probably depends on you memory manager and how it doles out memory.

>>why if I change AllocString(strlen(s), &copy); to AllocString(strlen(s)-7, &copy); I can still get a good result?


AllocString() doesn't actually copy anything into the newly allocate memory but just returns a pointer to it. If you allocate fewer bytes than you try to copy into that memory the outcome will be unpredictable. malloc() will normally allocate more space than what you requested because from a memory management point of view it's just easier and quicket to do that. It will most likely round the amount of memroy up to the nearest 8 or 16 bytes, which guarentees proper alignment for numeric data. But your program can not, or should not, count on that because that behavior can change at any time. For example Microsoft C compilers will add more memory when compiled for debug than for release modes. That's because the compiler might add more code to the program to do runtime buffer overflow checking. Other compilers may or may not act similarily.

Thanks Ancient Dragon!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.