look at the two line c code and output:
code:
char * str = "hello world!";
printf("h at heap memory address: %p\n",str);
printf("str pointer stack memory address: %p\n",&str);
and output:
h at heap memory address: 0x4008a8
str pointer stack memory address: 0x7ffc9e7ceb90
the memory address length for heap and stack is 0x4008a8, 0x7ffc9e7ceb90 respectively. Why memory address for heap is 3 bytes whereas memory address for stack is 6 bytes? Something related to virtual memory and paging ?
Try this instead:
char * str = "hello world!";
printf("h at heap memory address: %p (%zu bytes)\n", str, sizeof(str));
printf("str pointer stack memory address: %p (%zu bytes)\n", &str, sizeof(&str));
Using the sizeof operator, we can print the actual size of the two pointers. (%zu is a format specifier for an unsigned result from sizeof—it is probably equivalent to %lu on your system.)
You'll see that in both cases, the pointer actually takes up 8 bytes (64 bits).
The reason that the hexidecimal representations displayed by printf only show 3 or 6 bytes is because printf drops any leading zeros. Consider this similar example:
int i = 10;
printf("%x\n", i);
The result will just be "a", but that doesn't mean that i only takes up one byte.
#JohnathanLeffler nailed it. "The string literal is probably stored in the code [data] segment, where it will be non-writable." You can see this with a little more probing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Do this in a function so I can verify what is stack and what is heap.
* Try to return a variable and see if the compiler warns that it's
* stack memory!
*/
static char *test_mem() {
char *stack = "whom";
char *heap = malloc(sizeof(char) * 5);
printf("char *stack = \"%s\" at %p (size %zu) inner %p (size %zu)\n",
stack, stack, sizeof(stack), &stack, sizeof(&stack));
printf("char *heap = malloc at %p (size %zu) inner %p (size %zu)\n",
heap, sizeof(heap), &heap, sizeof(&heap));
return heap;
}
int main(void)
{
char *ret = test_mem();
printf("%s\n", ret);
return 0;
}
char *stack = "whom" at 0x102fc0f28 (size 8) inner 0x7fff5cc3f4d8 (size 8)
char *heap = malloc at 0x7f9362404c80 (size 8) inner 0x7fff5cc3f4d0 (size 8)
Note that only the string literal is in the lower memory address. All the rest are in basically the same location. When I open up the executable in a hex editor I can find a block of strings.
00000f20: dcff ffff 2573 0a00 7768 6f6d 0063 6861 ....%s..whom.cha
00000f30: 7220 2a73 7461 636b 203d 2022 2573 2220 r *stack = "%s"
00000f40: 6174 2025 7020 2873 697a 6520 257a 7529 at %p (size %zu)
00000f50: 2069 6e6e 6572 2025 7020 2873 697a 6520 inner %p (size
00000f60: 257a 7529 0a00 6368 6172 202a 6865 6170 %zu)..char *heap
00000f70: 203d 206d 616c 6c6f 6320 6174 2025 7020 = malloc at %p
00000f80: 2873 697a 6520 257a 7529 2069 6e6e 6572 (size %zu) inner
00000f90: 2025 7020 2873 697a 6520 257a 7529 0a00 %p (size %zu)..
The string foo is not stored in the heap, it is in the data segment of the executable which, as you guessed, is accessed as virtual memory which is allocated a special range.
Finally, the output shows those pointers are all of the same size. They're all (in my case) 64 bit (8 byte) pointers.
Explanation
Note that pointers are still variables in C and the only thing that makes them special is that they have the special * notation beside them. The value of a pointer is the address it refers to, just like the value of an int is the value it is assigned to
char * str = "hello world!";
printf("h at heap memory address: %p\n",str);
printf("str pointer stack memory address: %p\n",&str);
They both use the pointer specifier (%p) which is used to print memory address of a value. Note this is implementation defined.
The first one prints the memory address of the string literal "hello world!", i.e. the value of the pointer str
The second prints the memory address of the pointer i.e. the memory address of str
As for why these values are so far apart, #DaoWen already answered this and it has nothing to do with virtual pages or whatnot.
Related
This question already has answers here:
Using sizeof() on malloc'd memory [duplicate]
(5 answers)
Newbie questions about malloc and sizeof
(8 answers)
Closed 1 year ago.
I'm learning C dynamic memory allocation and can't figure out why malloc or calloc are not allocating the amount of memory specified for the struct array, nor for the name char array.
Code example:
struct spaceShip{
long long int distance; // 8 bytes
int numParts; // 4 bytes
char *name; // 1 byte
}; // 13 bytes total
int main (int argc, char *argv[]){
int amount=10;
struct spaceShip *spaceShipArray;
printf("size of struct spaceShip = %d bytes\n", sizeof(struct spaceShip));
spaceShipArray = malloc(amount * sizeof(*spaceShipArray));
printf("size of spaceShipArray = %d bytes\n", sizeof(*spaceShipArray));
spaceShipArray[0].name = malloc(100 * sizeof(char));
printf("size of name char array = %d \n", sizeof(spaceShipArray[0].name));
free(spaceShipArray);
return 0;
}
Output:
size of struct spaceShip = 16 bytes //I guess because of the pagination mechanism it takes more?
size of spaceShipArray = 16 bytes // not ok. should be 160
size of name char array = 4 // not ok. should be 100
For starters to output objects of the type size_t you have to use the conversion specifier %zu. For example
printf("size of struct spaceShip = %zu bytes\n", sizeof(struct spaceShip));
These two statements
printf("size of struct spaceShip = %zu bytes\n", sizeof(struct spaceShip));
printf("size of spaceShipArray = %zu bytes\n", sizeof(*spaceShipArray));
output the same value because the expression sizeof(*spaceShipArray) is equivalent to the expression sizeof(struct spaceShip).
That is dereferencing the pointer spaceShipArray gives an object of the type struct spaceShip. Pointers know nothing whether they point to a single object or a first element of an array.
If you want to output the size of the allocated memory then you should write for example
printf("size of spaceShipArray = %zu bytes\n", amount * sizeof(*spaceShipArray));
This statement
printf("size of name char array = %zu \n", sizeof(spaceShipArray[0].name));
outputs the size of a pointer of the type char * because it is the type of the expression spaceShipArray[0].name.
So the program output is correct.
Take into account that you forgot to free the memory allocated for a character array. For example
free( spaceShipArray[0].name );
free(spaceShipArray);
First output: char* uses 4 bytes on a old computer (32bit) or 8 bytes on a modern computer (64bit) because it is a pointer (not a single char).
Second output: it is correct because it's the size of a single element of the vector (16 byte)
Third output: it is correct because sizeof returns the size of the char pointer (4 bytes on a 32bit computer)
This is an example from a book I am reading, to demonstrate the use of heap memory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *char_ptr;
int *int_ptr;
int mem_size;
if (argc < 2) //if not given an argument, defaukt memory size is 50//
mem_size = 50;
else
mem_size = atoi(argv[1]);
printf("\t[+] allocating %d bytes of memory on the heap for char_ptr\n", mem_size); //memory is given, and passed to char pointer//
char_ptr = (char *)malloc(mem_size);
if(char_ptr == NULL) { //check for error//
fprintf(stderr, "Error: could not allocate memory.\n");
exit(-1);
}
strcpy(char_ptr, "This memory is located on the heap.");
printf("char_ptr (%p) --> '%s'\n", char_ptr, char_ptr);
printf("\t[+] allocating 12 bytes of memory on the heap for int_ptr\n");
int_ptr = (int *)malloc(12);
if(int_ptr == NULL) {
fprintf(stderr, "Error: coud not allocate heap memory.\n");
exit(-1);
}
*int_ptr = 31337;
printf("int_ptr (%p) --> %d\n", int_ptr, *int_ptr);
printf("\t[-] freeing char_ptr's heap memory...\n");
free(char_ptr);
printf("\t[+] allocating another 15 bytes for char_ptr\n");
char_ptr = (char *)malloc(15);
if(char_ptr == NULL) {
fprintf(stderr, "Error: coud not allocate heap memory.\n");
exit(-1);
}
strcpy(char_ptr, "new memory");
printf("char_ptr (%p) --> '%s'\n", char_ptr, char_ptr);
printf("\t[-] freeing int_ptr's heap memor...\n");
free(int_ptr);
}
I am confused about this line: strcpy(char_ptr, "This memory is located on the heap.");
char_ptr already contains the address of allocated heap memory, so how does this text get copied into the pointer? It seems the address of allocated heap memory also did not change, from looking at printf("char_ptr (%p) --> '%s'\n", char_ptr, char_ptr);. Does this basically mean the pointer contains two values? How does this work?
kingvon#KingVon:~/Desktop/asm$ ./a.out
[+] allocating 50 bytes of memory on the heap for char_ptr char_ptr (0x55ef60d796b0) --> 'This memory is located on the heap.'
[+] allocating 12 bytes of memory on the heap for int_ptr int_ptr (0x55ef60d796f0) --> 31337
[-] freeing char_ptr's heap memory...
[+] allocating another 15 bytes for char_ptr char_ptr (0x55ef60d79710) --> 'new memory'
[-] freeing int_ptr's heap memor...
[-] freeing char_ptr's heap memory...
Does this basically mean the pointer contains two values?
No – the char_ptr variable can only have one particular value – that will be (following a successful call to malloc) the starting address of a block of the specified number of bytes in memory. Just that – an address.
What may be confusing you is how that address is used/interpreted in your subsequent code.
The strcpy(char_ptr, "This memory is located on the heap."); line uses that address when it copies the data from the second argument (the string literal) into the bytes starting at that address – and it continues doing so until it finds the nul-terminator at the end of that literal (which it will also copy, and then stop).
The printf("char_ptr (%p) --> '%s'\n", char_ptr, char_ptr); call is a bit more subtle. Although you are giving the same address (exactly) as both arguments, the way that address is interpreted by the printf function is determined by the corresponding format arguments. For the first instance, the %p specifier tells the function to print the actual value of the address; for the second instance, the %s specifier tells it to print out the characters, in order, starting at the given address, and stopping when it finds the first nul (zero) character.
strcpy copies a null terminated C string into the memory pointed to by the first argument.
No it does not contain two values. A pointer has its own value which is a memory address, and it POINTS TO the values at that memory address. That can be one thing, or an array of things. In the case of a character pointer it is the first character in an array. An array of characters with a NUL, aka 0 character at the end is a C string.
I have written a code which at first creates a memory alloc and save a string in an other pointer. According to the code, the value must be kept in an other address after free but it gives an error "munmap_chunk(): invalid pointer".
My Code is :
#include <stdio.h>
#include <stdlib.h>
#include "testfunc.h"
#include <string.h>
int main()
{
static char *server_alg;
char *test;
char *test = (char*) malloc(30*sizeof(char));
server_alg = "A";
strcpy(test, server_alg);
printf("server_alg addr = %u \n", &*server_alg);
printf("server_alg value = %u \n", server_alg);
printf("SERVER_ALGO addr = %d \n", *server_alg);
free(server_alg);
server_alg=NULL;
printf(" nulled \n");
printf("server_alg addr = %u \n", &*server_alg);
printf("server_alg value = %u \n", server_alg);
printf("SERVER_ALGO addr = %u \n", test);
printf("SERVER_ALGO value = %u \n", *test);
return 0;
}
Is it wrong?
Thx for your helps
You are freeing server_alg, but you didn't allocate any memory there. Instead, you assigned a string literal to it, so it's pointing to a read-only location in your program's binary:
server_alg = "A";
After this, you copy from that pointer to test:
strcpy(test, server_alg);
This is correct, as you properly allocated memory for test here:
char *test = (char*) malloc(30*sizeof(char));
Then, however, you try to free it while it is still pointing to "A" in your binary:
free(server_alg);
Instead, try freeing test, because that is pointing to the memory you allocated:
free(test);
test=NULL;
Furthermore, there's an issue with redeclaration here:
char *test;
char *test = (char*) malloc(30*sizeof(char));
You're defining test twice, best just remove that first line.
Last but not least, I'd change the prints in the end to:
printf("server_alg addr = %p \n", server_alg); // 00D87B30 (or something similar)
printf("server_alg value = %s \n", server_alg); // A
printf("SERVER_ALGO addr = %p \n", test); // 00000000
//printf("SERVER_ALGO value = %u \n", *test);
%s is the specifier that lets you print a string, and %p is the one for pointers. I commented out that last print because it would crash the program as test is freed and set to a null pointer now, so we can't access its content.
On another note, when you want to copy a string to the heap (be it from a string literal or from a different place on the stack heap), strdup can be used to do that. It allocates the appropriate amount of memory so you don't have to worry about that. Call it like this:
char *test = strdup("A");
When you're done with it, you free it by calling free(test);, just like with memory allocated by malloc.
following statements are the issues here
free(server_alg);
you can use free() only when if you allocate memory using one of malloc(), calloc() or realloc() as you have not allocated memory free(server_alg); is wrong, it will lead to memory dump
and we should never try to use pointer once we do free() on it.
I'm currently attempting to learn the C side of C++.
I attempt to malloc a chunk of memory for a char array of 256 and then I assigned it a char* "Hello World!" but when I come to free the object I get an error.
Can anyone please explain to me the error.
#include <exception>
#include <stdexcept>
#include <iostream>
int main()
{
void* charVoidPointer = malloc( sizeof(char) * 256 ) ;
charVoidPointer = "Hello World";
std::cout << (char *)charVoidPointer;
free (charVoidPointer);
}
"Hello World" is statically allocated by the compiler. It is part of the program and exists at some place addressable by the program; call it address 12.
charVoidPointer initially points to some place allocated for you by malloc; call it address 98.
charVoidPointer = "Hello ..." causes charVoidPointer to point to the data in your program; address 12. You lose track of address 98 previously contained in charVoidPointer.
And you can't free memory not allocated by malloc.
To demonstrate more literally what I mean:
void* charVoidPointer = malloc(sizeof(char) * 256);
printf("the address of the memory allocated for us: %p\n", charVoidPointer);
charVoidPointer = "Hello World";
printf("no longer the address allocated for us; free will fail: %p\n",
charVoidPointer);
What you meant was:
strcpy(charVoidPointer, "Hello World");
Edit: Example of addressing memory for other types
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
// an array of 10 int
int *p = (int*)malloc(sizeof(int) * 10);
// setting element 0 using memcpy (works for everything)
int src = 2;
memcpy(p+0, &src, sizeof(int));
// setting element 1 using array subscripts. correctly adjusts for
// size of element BECAUSE p is an int*. We would have to consider
// the size of the underlying data if it were a void*.
p[1] = 3;
// again, the +1 math works because we've given the compiler
// information about the underlying type. void* wouldn't have
// the correct information and the p+1 wouldn't yield the result
// you expect.
printf("%d, %d\n", p[0], *(p+1));
free (p);
}
Experiment; Change the type from int to long, or double, or some complex type.
void* charVoidPointer = malloc( sizeof(char) * 256 ) ;
now charVoidPointer (weird name by the way - if you want chars, use char * and cast the pointer returned from malloc) points at a block of 256 characters. This block is uninitialized, so almost the only valid thing you can do is set them all to some value, or copy something in.
charVoidPointer = "Hello World";
now charVoidPointer points instead at a statically-allocated character array, and you've lost the address returned by malloc. There is no way to get it back, so this is a resource leak.
Your code should look something like:
char *charPointer = (char *)malloc(256);
strcpy(charPointer, "Hello World");
which copies the character array into your allocated block. Or, more concisely, just
char *charPointer = strdup("Hello World");
which will allocate a block just the right size and copy the string in. You still release the block with free.
Use strcpy(charVoidPointer, "Hello World"); because in your example you reassign your pointer.
You're assigning the pointer to the address of the string literal "Hello World", therefore the memory block you malloc'ed is leaked.
You should use
strcpy(charVoidPointer, "Hello World");
instead of the assignment operator.
Even better is to use strncpy(charVoidPointer, "Hello World", 255); to avoid overflowing the array you allocate.
Pointer Downcast
int* ptrInt;
char * ptrChar;
void* ptrVoid;
unsigned char indx;
int sample = 0x12345678;
ptrInt = &sample;
ptrVoid = (void *)(ptrInt);
ptrChar = (char *)(ptrVoid);
/*manipulating ptrChar */
for (indx = 0; indx < 4; indx++)
{
printf ("\n Value: %x \t Address: %p", *(ptrChar + indx), ( ptrChar + indx));
}
Output:
Value: 00000078 Address: 0022FF74
Value: 00000056 Address: 0022FF75
Value: 00000034 Address: 0022FF76
Value: 00000012 Address: 0022FF77
Question:
Why was sample divided into char sized data? And when pointer arithmetic is performed, how was it able to get its remaining value?
How this was possible?
Pointer Upcast
unsigned int * ptrUint;
void * ptrVoid;
unsigned char sample = 0x08;
ptrVoid = (void *)&sample;
ptrUint = (unsigned int *) ptrVoid;
printf(" \n &sample: %p \t ptrUint: %p ", &sample, ptrUint );
printf(" \n sample: %p \t *ptrUint: %p ", sample, *ptrUint );
Output:
&sample: 0022FF6F ptrUint: 0022FF6F
sample: 00000008 *ptrUint: 22FF6F08 <- Problem Point
Question:
Why is it that there is a garbage value in *ptrUint? Why is the garbage value similar
to ptrUint? Should malloc() or calloc() be used to avoid this garbage value? What kind of remedy would you suggest to remove the garbage value?
In the first example, you are using a char pointer so the data is going to be accessed a byte at a time. Memory is byte addressable, so when you add one to a pointer, you will access the next higher memory address. This is what is happening with the for loop. Using a byte pointer tells the compiler to access only the single byte, and rest of bits will show up as 0 when you are printing with %p.
In the second example, I think what is happening is that one byte is allocated for the sample byte, then the following 4 bytes were allocated to the ptrUint. So when you get the value starting at the memory address of sample and converting it to a 4 byte pointer, you just see the value in Sample plus the first 3 bytes of the ptrUint. If you cast this to a char pointer, and print, you would only see 8 in the output.
These aren't upcasts and downcasts, that would imply some kind of inheritance hierarchy.
In your first example you treat a pointer to an integer like if it was a pointer to char(s). Incrementing a pointer to int adds 4 to it, incrementing a pointer to char adds 1 to it (assuming 32 bit ints and 8 bit chars). Dereferencing them makes an int and a char, respectively. Hence the fragmentation into bytes.
In your second example you treat the unsigned char variable called sample as if it were a pointer to int, and dereference it. You are essentially reading garbage from the 0x08 memory address. I suppose you forgot a &. You are also passing a 1 byte char and a 4 byte int to the second printf, instead of 4+4 bytes, that messes up printf, reading 3 bytes more from the stack than you have given him. Which coincidentally is part of the ptrUint value given to the first call of printf. Using %c instead of %p should fix it.
The other answers have already explained why you're seeing what you're seeing.
I will add that your second example relies on undefined behaviour. It is not valid to dereference an int * that points to data that wasn't originally an int. i.e.:
char x = 5;
int *p = (int *)&x;
printf("%d\n", *p); // undefined behaviour