-1

I have the following program : My program compiles fine and gives the output as mentioned below . I have some question on output which is listed at the bottom. *******************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
    char *p = malloc(sizeof(char));
    char *q = malloc(sizeof(char));
    printf("address of p = %p \n", p); A
    printf("address of q = %p \n", q); B
    strcpy(p, "abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz");
    printf("Value in P : %s \n", p); C
    printf("Value in q : %s\n", q); D
    printf("string length of P : %d \n", strlen(p)); E
    printf("string lenght of q : %d\n", strlen(q)); F

    return 0;
}

===OUTPUT ==
address of p = 0xbbf010 
address of q = 0xbbf030 
Value in P : abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz 
Value in q : 789abcdefghijklmnopqrstuvwxyz
string length of P : 61 
string lenght of q : 29

=====OUTPUT END==

Questions :
1. Why there is a difference of 32 bytes between address of p and q. I have allocated 1 byte only for P. How automatically 32 byte difference between successive malloc?
2. I have not NULL terminated my Strings. How printf detecting the \0 termination?
3. How strlen is also working fine without a \0 termination?

UnholySheep
  • 3,967
  • 4
  • 19
  • 24
JDS
  • 1
  • 2
    `strcpy(p, "abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz");` invokes *undefined behavior* - any results you get from this code are meaningless – UnholySheep Dec 30 '19 at 18:01
  • 4
    `char *p = malloc(sizeof(char));` = you allocate 1 byte and copy a far longer string later on to this address, so you're overwriting random memory locations (@UnholySheep) And the addresses differ by more than 1 byte because memory is usually allocated on aligned addresses. How it is aligned differs by compiler and system, but usually alignments are on 4, 8, 16 or 32 byte boundaries. – Alex B Dec 30 '19 at 18:03
  • 1
    The zero-termination is caused by strcpy. Look it up :-) – Alex B Dec 30 '19 at 18:06
  • @AlexB why not make an answer out of your two comments? – Matthieu Dec 30 '19 at 18:12
  • 1
    @infinite chars can start on any byte address, but malloc always allocates aligned storage. Which alignment it chooses is undefined. – Alex B Dec 30 '19 at 18:14
  • 1
    "abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz" has a null and strcpy copies the null. – JaeMann Yeh Dec 30 '19 at 18:15
  • 1
    Just did, thanks for the heads-up @Matthieu – Alex B Dec 30 '19 at 18:22
  • 1
    `NULL` is (a macro that expands to) a *null pointer constant*. It's not related to the *null character* that terminates a string. Strings are null-terminated, not NULL-terminated. – Keith Thompson Dec 30 '19 at 20:55

2 Answers2

2
  1. Why there is a difference of 32 bytes between address of p and q. I have allocated 1 byte only for P. How automatically 32 byte difference between successive malloc?

Because that's how your implementation chooses to do it. There's no requirement for any particular relationship between the return values of any two calls to malloc(), even consecutive ones such as yours.

In practice, C implementations tend to allocate memory with multi-byte granularity, even when the requested size is less, and that's what you appear to be observing. That absolutely does not mean it's ok to access memory beyond the boundaries of what you explicitly requested.

  1. I have not NULL terminated my Strings. How printf detecting the \0 termination?
  2. How strlen is also working fine without a \0 termination?

Who says your strings are not terminated? The string literal certainly is. Beyond that, you produce undefined behavior by overrunning the bounds of the allocated space to which p points, so anything can happen.

If you want to speculate about the UB then you might guess based on the observed output that the strcpy copies bytes from the source string into the memory starting at *p, continuing through all the unallocated bytes between that and *q, and on into the unallocated space beyond *q until eventually it copies the nul byte. You might then guess that printf and strlen similarly read from one or the other starting point into the unallocated regions.

That might or might not accurately describe what actually happens, and under no circumstance should you interpret the observed results as an indication that such program behavior is either predictable or acceptable. In particular, such behavior often produces corruption of the allocator's metadata, which might manifest when you attempt to free the allocated space or allocate other space.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1
  1. You allocate 1 byte of storage for both p and q
  2. You copy a string far longer than that (in fact, any string longer than an empty string wouldn't fit) to p, which triggers undefined behavior.

Since the C std lib underneath the compiler (its malloc implementation in fact) seems to choose 32 byte aligned allocations and since no other allocations happen in between, the two pointers are in your case 32 bytes apart.

strcpy copies the too-long string to p including a zero-terminator (see c docs).

q will thus point to p + 32 bytes, explaining the remaining behavior.

Side note: If you're approaching C, especially as a beginner, always have the docs ready. Undefined behavior strikes more often than not.

Alex B
  • 354
  • 1
  • 9