I'm very confused about what's happening. I always thought char * and char [] were interchangable, but after looking at the memory addresses it seems char * allocates space in the heap, whereas char [] is allocating memory on the stack.
char stack[] = "hello";
char *heap = "hello";
char *heap_string_malloc = malloc(5);
heap_string_malloc = "hello";
printf("Address of stack[0]: %p\n", stack);
printf("Address of heap[0]: %p\n", heap);
printf("Address of heap_string_malloc[0]: %p\n", heap_string_malloc);
Outputs the following:
Address of stack[0]: 0x7fff8b0b85b0
Address of heap[0]: 0x400760
Address of heap_string_malloc[0]: 0x400760
Does this mean that char * is dynamically allocated?
Further to my confusion, how come malloc is allocating the same memory address as what char *heap has already allocated? I'm not running any optimisation (simply gcc file.c).
Arrays are not pointers. What your program is doing, line by line, is
// Allocate 6 bytes in the stack and store "hello" in them
char stack[] = "hello";
// Allocate pointer on the stack and point it to a static, read-only buffer
// containing "hello"
char *heap = "hello";
// Malloc 5 bytes (which isn't enough to hold "hello" due to the NUL byte)
char *heap_string_malloc = malloc(5);
// Reset heap_string_malloc to point to a static buffer; memory leak!
heap_string_malloc = "hello";
The reason you're seeing the same pointer twice is because the compiler optimized away the second static buffer containing "hello".
When you do e.g.
char *heap = "hello";
the pointer heap actually does not point to the heap, it points to static data loaded together with the rest of program by the operating system loader. In fact, to be correct it should be
const char *heap = "hello";
as heap is pointing to a constant and read-only piece of memory.
Also, while arrays decays to (and can be used as) pointers, and pointers can be used with array syntax, they are not the same. The biggest difference being that for an array you can use e.g. sizeof to get the size in bytes of the actual array, while it's not possible for pointers.
And as a third thing, when you're doing
char *heap_string_malloc = malloc(5);
heap_string_malloc = "hello";
you have a memory leak, as you first assign something to heap_string_malloc but then directly afterward reassign heap_string_malloc to point to something completely different.
As for the reason you get the same address for both heap and heap_string_malloc it's because both points to the same literal string.
String literals such as "hello" are stored in such a way that they are held over the lifetime of the program. They are often stored in a separate data segment (distinct from the stack or heap) which may be read-only.
When you write
char stack[] = "hello";
you are creating a new auto ("stack") variable of type "6-element array of char" (size is taken from the length of the string literal), and the contents of the string literal "hello" are copied to it.
When you write
char *heap = "hello";
you are creating a new auto ("stack") variable of type "pointer to char", and the address of the string literal "hello" is copied to it.
Here's how it looks on my system:
Item Address 00 01 02 03
---- ------- -- -- -- --
"hello" 0x400b70 68 65 6c 6c hell
0x400b74 6f 00 22 68 o."h
stack 0x7fffb00c7620 68 65 6c 6c hell
0x7fffb00c7624 6f 00 00 00 o...
heap 0x7fffb00c7618 70 0b 40 00 p.#.
0x7fffb00c761c 00 00 00 00 ....
*heap 0x400b70 68 65 6c 6c hell
0x400b74 6f 00 22 68 o."h
As you can see, the string literal "hello" has its own storage, starting at address 0x400b70. Both the stack ahd heap variables are created as auto ("stack") variables. stack contains a copy of the contents of the string literal, while heap contains the address of the string literal.
Now, suppose I use malloc to allocate the memory for the string and assign the result to heap:
heap = malloc( sizeof *heap * strlen( "hello" + 1 ));
strcpy( heap, "hello" );
Now my memory map looks like the following:
Item Address 00 01 02 03
---- ------- -- -- -- --
"hello" 0x400b70 68 65 6c 6c hell
0x400b74 6f 00 22 68 o."h
stack 0x7fffb00c7620 68 65 6c 6c hell
0x7fffb00c7624 6f 00 00 00 o...
heap 0x7fffb00c7618 10 10 50 00 ..P.
0x7fffb00c761c 00 00 00 00 ....
*heap 0x501010 68 65 6c 6c hell
0x501014 6f 00 00 00 o...
The heap variable now contains a different address, which points to yet another 6-byte chunk of memory containing the string "hello".
EDIT
For byteofthat, here's the code I use to generate the above map:
dumper.h:
#ifndef DUMPER_H
#define DUMPER_H
/**
* Dumps a memory map to the specified output stream
*
* Inputs:
*
* names - list of item names
* addrs - list of addresses to different items
* lengths - length of each item
* count - number of items being dumped
* stream - output destination
*
* Outputs: none
* Returns: none
*/
void dumper(char **names, void **addrs, size_t *lengths, size_t count, FILE *stream);
#endif
dumper.c:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "dumper.h"
/**
* Dumps a memory map to the specified output stream
*
* Inputs:
*
* names - list of item names
* addrs - list of addresses to different items
* lengths - length of each item
* count - number of items being dumped
* stream - output destination
*
* Outputs: none
* Returns: none
*/
void dumper(char **names, void **addrs, size_t *lengths, size_t count, FILE *stream)
{
size_t i;
int maxlen = 15;
for ( size_t j = 0; j < count; j++ )
{
if (strlen(names[j]) > maxlen && strlen(names[j]) < 50)
maxlen = strlen(names[j]);
}
fprintf(stream,"%*s%15s%5s%5s%5s%5s\n", maxlen, "Item", "Address", "00", "01",
"02", "03");
fprintf(stream,"%*s%15s%5s%5s%5s%5s\n", maxlen, "----", "-------", "--", "--",
"--", "--");
for (i = 0; i < count; i++)
{
size_t j;
char *namefield = names[i];
unsigned char *p = (unsigned char *) addrs[i];
for (j = 0; j < lengths[i]; j+=4)
{
size_t k;
fprintf(stream,"%*.*s", maxlen, maxlen, namefield);
fprintf(stream,"%15p", (void *) p);
for (k = 0; k < 4; k++)
{
fprintf(stream,"%3s%02x", " ", p[k]);
}
fprintf(stream, " ");
for ( k = 0; k < 4; k++)
{
if (isgraph(p[k]))
fprintf(stream,"%c", p[k]);
else
fprintf(stream, ".");
}
fputc('\n', stream);
namefield = " ";
p += 4;
}
fputc('\n', stream);
}
}
And an example of how to use it:
#include <stdio.h>
#include "dumper.h"
int main(void)
{
int x = 0;
double y = 3.14159;
char foo[] = "This is a test";
void *addrs[] = {&x, &y, foo, "This is a test"};
char *names[] = {"x", "y", "foo", "\"This is a test\""};
size_t lengths[] = {sizeof x, sizeof y, sizeof foo, sizeof "This is a test"};
dumper(names, addrs, lengths, 4, stdout);
return 0;
}
This creates an array on the stack, containing a copy of the static string "hello":
char stack[] = "hello";
This creates a pointer on the stack, containing the address of the static string "hello":
char *heap = "hello";
This creates a pointer on the stack, containing the address of a dynamically allocated buffer of 5 bytes:
char *heap_string_malloc = malloc(5);
But in all three cases, you put something on the stack. char* is not "on the heap". It is a pointer (on the stack) which points to something, somewhere.
"stack" is a static array of chars so it will be allocated in the stack and freed automatically once the function ends, because its size is known since its definition.
While "heap" and "heap_string_malloc" are both declared as pointers to char buffers and need to be allocated dynamicly with malloc in order to define the size of their content, that's why they will reside in the heap memory.
By doing:
char *heap = "hello";
and:
heap_string_malloc = "hello";
you are modifying the pointers them-self (with a static buffer value), not the content to which they're pointing. You should rather use memcpy to modify the memory pointed by the "heap_string_malloc" pointer with your data:
memcpy(heap_string_malloc, "hello", 5);
Related
below program does not run as we are returning local int value.
#include<stdio.h>
int *fun1()
{
int i = 10;
return &i; // local i hence will not get printed in main
}
main()
{
int *x = fun1();
printf("%d", *x);
}
However, at the same time below program runs, even though we are returning local string base address. Why the concept of local char* does not apply here?
char *fun()
{
char *p = "ram";
return p; //char* is local, even though in main it gets printed. why?
}
int main()
{
char *x = fun();
printf("%s", x);
return 0;
}
char *fun()
{
char *p = "ram";
return p; //char* is local, even though in main it gets printed. why?
}
When you write code like this, "ram" does not get placed on the stack the same way that int i = 10 does - it gets placed in the .rodata (read only data) section of the executable. What gets placed on the stack is a pointer to this location in memory.
Imagine if "ram" wasn't three characters, but a million characters - if the string itself were to be pushed onto the stack, a million bytes would have to be pushed to the stack every time the function was called! Even though the string is constant.
Since the location of the string in memory is constant, it is valid to return a pointer to that location.
In this function
int *fun1()
{
int i = 10;
return &i; // local i hence will not get printed in main
}
the block scope variable i has automatic storage duration. It means that after exiting the function the variable will not be alive and the returned pointer to the variable will be invalid.
In this function
char *fun()
{
char *p = "ram";
return p; //char* is local, even though in main it gets printed. why?
}
the string literal "ram" having the type char[4] has static storage duration. It means that it is will be alive after exiting the function and the returned pointer to the literal will be valid.
From the C Standard (6.4.5 String literals)
6 In translation phase 7, a byte or code of value zero is appended to
each multibyte character sequence that results from a string literal
or literals.78) The multibyte character sequence is then used to
initialize an array of static storage duration and length just
sufficient to contain the sequence.
Pay attention to that the function returns a copy of the pointer p but the pointed object (the string literal) has static storage duration. So the returned pointer has a valid value.
You can achieve the same effect in the first function by declaring the variable i as having static storage duration. For example
int *fun1()
{
static int i = 10;
return &i; // local i hence will not get printed in main
}
As for your question written by you as an answer
And why below does not work? when i changed from char *p = "ram" to
char p[]="ram" ?
char *fun()
{
char p[] = "ram";
return p;
}
int main()
{
char *x = fun();
printf("%s", x);
return 0;
}
then the array p is a local array with automatic storage duration of the function. Its elements are initialized by elements of the string literal "ram". But this does change the array storage duration. In fact this declaration of the array is similar to
char p[] = { 'r', 'a', 'm', '\0' };
So this return statement
return 0;
returns a pointer to the first element of the array that (array) will not be alive after exiting the function. So the returned pointer will be invalid.
In the code
char *fun()
{
char *p = "ram";
return p; //char* is local, even though in main it gets printed. why?
}
The variable p is local to the function, and its lifetime ends with the function. However, you are returning p's value, not its address, so that doesn't really matter here.
p's value is the address of the string literal "ram". String literals are stored in such a way that they are available over the lifetime of the entire program, from startup to termination - the literal "ram" does not cease to exist when fun exits, so its address stays valid.
And why below does not work? when i changed from char *p = "ram" to char p[]="ram" ?
Now you've changed how and where the string gets stored. Instead of p being a pointer that stores the address of the string literal, it is now an array that stores the contents of the string itself. The lifetime of the string is now the same as the lifetime of the function, so once the function exits, the array that stored that string no longer exists and the return value is not valid.
I took your code and added a utility1 to display the address and contents of various items in memory. First we start with the first version where p is a pointer:
#include <stdio.h>
#include "dumper.h"
char *fun( void )
{
char *p = "ram";
char *names[] = { "p", "\"ram\"" };
void *addrs[] = { &p, "ram" };
size_t sizes[] = { sizeof p, sizeof "ram" };
puts( "In fun: ");
dumper( names, addrs, sizes, 2, stdout );
return p;
}
int main( void )
{
char *x;
char *names[] = { "x", "\"ram\"" };
void *addrs[] = { &x, "ram" };
size_t sizes[] = { sizeof x, sizeof "ram" };
puts( "Before call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
x = fun();
puts( "After call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
return 0;
}
And here's the output:
Before call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee2451a40 a0 1a 45 e2 ..E.
0x7ffee2451a44 fe 7f 00 00 ....
"ram" 0x10d7aef04 72 61 6d 00 ram.
In fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
p 0x7ffee24519b8 04 ef 7a 0d ..z.
0x7ffee24519bc 01 00 00 00 ....
"ram" 0x10d7aef04 72 61 6d 00 ram.
After call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee2451a40 04 ef 7a 0d ..z.
0x7ffee2451a44 01 00 00 00 ....
"ram" 0x10d7aef04 72 61 6d 00 ram.
First, notice that the string literal "ram" has the same address in both fun and main. Again, string literals are allocated such that they are available over the lifetime of the program. You'll notice its address is much lower than the other items, indicating it's in a very different region of memory.
Again, notice that p only stores the address of the string, not its contents. So even though p ceases to exist, its value continues to be valid.
Now, we change that code so that p is an array, not a pointer:
#include <stdio.h>
#include "dumper.h"
char *fun( void )
{
char p[] = "ram";
char *names[] = { "p", "\"ram\"" };
void *addrs[] = { &p, "ram" };
size_t sizes[] = { sizeof p, sizeof "ram" };
puts( "In fun: ");
dumper( names, addrs, sizes, 2, stdout );
return p;
}
int main( void )
{
char *x;
char *names[] = { "x", "\"ram\"" };
void *addrs[] = { &x, "ram" };
size_t sizes[] = { sizeof x, sizeof "ram" };
puts( "Before call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
x = fun();
puts( "After call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
return 0;
}
Now our output looks like this:
Before call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee059ea40 98 ea 59 e0 ..Y.
0x7ffee059ea44 fe 7f 00 00 ....
"ram" 0x10f661efc 72 61 6d 00 ram.
In fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
p 0x7ffee059e9bc 72 61 6d 00 ram.
"ram" 0x10f661efc 72 61 6d 00 ram.
After call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee059ea40 bc e9 59 e0 ..Y.
0x7ffee059ea44 fe 7f 00 00 ....
"ram" 0x10f661efc 72 61 6d 00 ram.
Instead of storing the address of the string literal, p now stores the contents of the string itself. Once fun exits, p (and by extension the string it contains) ceases to exist.
Available here
below program does not run as we are returning local int value.
#include<stdio.h>
int *fun1()
{
int i = 10;
return &i; // local i hence will not get printed in main
}
main()
{
int *x = fun1();
printf("%d", *x);
}
However, at the same time below program runs, even though we are returning local string base address. Why the concept of local char* does not apply here?
char *fun()
{
char *p = "ram";
return p; //char* is local, even though in main it gets printed. why?
}
int main()
{
char *x = fun();
printf("%s", x);
return 0;
}
char *fun()
{
char *p = "ram";
return p; //char* is local, even though in main it gets printed. why?
}
When you write code like this, "ram" does not get placed on the stack the same way that int i = 10 does - it gets placed in the .rodata (read only data) section of the executable. What gets placed on the stack is a pointer to this location in memory.
Imagine if "ram" wasn't three characters, but a million characters - if the string itself were to be pushed onto the stack, a million bytes would have to be pushed to the stack every time the function was called! Even though the string is constant.
Since the location of the string in memory is constant, it is valid to return a pointer to that location.
In this function
int *fun1()
{
int i = 10;
return &i; // local i hence will not get printed in main
}
the block scope variable i has automatic storage duration. It means that after exiting the function the variable will not be alive and the returned pointer to the variable will be invalid.
In this function
char *fun()
{
char *p = "ram";
return p; //char* is local, even though in main it gets printed. why?
}
the string literal "ram" having the type char[4] has static storage duration. It means that it is will be alive after exiting the function and the returned pointer to the literal will be valid.
From the C Standard (6.4.5 String literals)
6 In translation phase 7, a byte or code of value zero is appended to
each multibyte character sequence that results from a string literal
or literals.78) The multibyte character sequence is then used to
initialize an array of static storage duration and length just
sufficient to contain the sequence.
Pay attention to that the function returns a copy of the pointer p but the pointed object (the string literal) has static storage duration. So the returned pointer has a valid value.
You can achieve the same effect in the first function by declaring the variable i as having static storage duration. For example
int *fun1()
{
static int i = 10;
return &i; // local i hence will not get printed in main
}
As for your question written by you as an answer
And why below does not work? when i changed from char *p = "ram" to
char p[]="ram" ?
char *fun()
{
char p[] = "ram";
return p;
}
int main()
{
char *x = fun();
printf("%s", x);
return 0;
}
then the array p is a local array with automatic storage duration of the function. Its elements are initialized by elements of the string literal "ram". But this does change the array storage duration. In fact this declaration of the array is similar to
char p[] = { 'r', 'a', 'm', '\0' };
So this return statement
return 0;
returns a pointer to the first element of the array that (array) will not be alive after exiting the function. So the returned pointer will be invalid.
In the code
char *fun()
{
char *p = "ram";
return p; //char* is local, even though in main it gets printed. why?
}
The variable p is local to the function, and its lifetime ends with the function. However, you are returning p's value, not its address, so that doesn't really matter here.
p's value is the address of the string literal "ram". String literals are stored in such a way that they are available over the lifetime of the entire program, from startup to termination - the literal "ram" does not cease to exist when fun exits, so its address stays valid.
And why below does not work? when i changed from char *p = "ram" to char p[]="ram" ?
Now you've changed how and where the string gets stored. Instead of p being a pointer that stores the address of the string literal, it is now an array that stores the contents of the string itself. The lifetime of the string is now the same as the lifetime of the function, so once the function exits, the array that stored that string no longer exists and the return value is not valid.
I took your code and added a utility1 to display the address and contents of various items in memory. First we start with the first version where p is a pointer:
#include <stdio.h>
#include "dumper.h"
char *fun( void )
{
char *p = "ram";
char *names[] = { "p", "\"ram\"" };
void *addrs[] = { &p, "ram" };
size_t sizes[] = { sizeof p, sizeof "ram" };
puts( "In fun: ");
dumper( names, addrs, sizes, 2, stdout );
return p;
}
int main( void )
{
char *x;
char *names[] = { "x", "\"ram\"" };
void *addrs[] = { &x, "ram" };
size_t sizes[] = { sizeof x, sizeof "ram" };
puts( "Before call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
x = fun();
puts( "After call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
return 0;
}
And here's the output:
Before call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee2451a40 a0 1a 45 e2 ..E.
0x7ffee2451a44 fe 7f 00 00 ....
"ram" 0x10d7aef04 72 61 6d 00 ram.
In fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
p 0x7ffee24519b8 04 ef 7a 0d ..z.
0x7ffee24519bc 01 00 00 00 ....
"ram" 0x10d7aef04 72 61 6d 00 ram.
After call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee2451a40 04 ef 7a 0d ..z.
0x7ffee2451a44 01 00 00 00 ....
"ram" 0x10d7aef04 72 61 6d 00 ram.
First, notice that the string literal "ram" has the same address in both fun and main. Again, string literals are allocated such that they are available over the lifetime of the program. You'll notice its address is much lower than the other items, indicating it's in a very different region of memory.
Again, notice that p only stores the address of the string, not its contents. So even though p ceases to exist, its value continues to be valid.
Now, we change that code so that p is an array, not a pointer:
#include <stdio.h>
#include "dumper.h"
char *fun( void )
{
char p[] = "ram";
char *names[] = { "p", "\"ram\"" };
void *addrs[] = { &p, "ram" };
size_t sizes[] = { sizeof p, sizeof "ram" };
puts( "In fun: ");
dumper( names, addrs, sizes, 2, stdout );
return p;
}
int main( void )
{
char *x;
char *names[] = { "x", "\"ram\"" };
void *addrs[] = { &x, "ram" };
size_t sizes[] = { sizeof x, sizeof "ram" };
puts( "Before call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
x = fun();
puts( "After call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
return 0;
}
Now our output looks like this:
Before call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee059ea40 98 ea 59 e0 ..Y.
0x7ffee059ea44 fe 7f 00 00 ....
"ram" 0x10f661efc 72 61 6d 00 ram.
In fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
p 0x7ffee059e9bc 72 61 6d 00 ram.
"ram" 0x10f661efc 72 61 6d 00 ram.
After call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee059ea40 bc e9 59 e0 ..Y.
0x7ffee059ea44 fe 7f 00 00 ....
"ram" 0x10f661efc 72 61 6d 00 ram.
Instead of storing the address of the string literal, p now stores the contents of the string itself. Once fun exits, p (and by extension the string it contains) ceases to exist.
Available here
it seems like i did not really understand how the memory allocation with pointers works.
Quick example:
I got a structure,
struct Friends{
char *firstname;
char *lastname;
};
if I do allocate memory now, it will get me
2x sizeof(char) = 2x 1Byte
but, doesnt the free memory I need depend on how many characters I fill it with?
example:
char array[10] needs 10x sizeof(char), 1byte for each character?
Everywhere I look they allocate the memory, before they know how much they will fill the structure with.
I got a structure,
struct Friends{
char *firstname;
char *lastname;
};
if I do allocate memory now, it will get me
2x sizeof(char) = 2x 1Byte
Instead of char's, you are allocating pointers here sizeof(char *). Depending on the system, those are 4 bytes (32-bit) or 8 bytes (64-bit) each.
So, if you want data where your pointers point to, you will have to allocate that, with malloc() for example, and free() them later.
Or do something like:
struct Friends{
char firstname[20];
char lastname[20];
};
But make sure your strings end with a \0 char.
Everywhere I look they allocate the memory, before they know how much
they will fill the structure with.
Yes and no.
struct Friends {
char *firstname;
char *lastname;
};
It all depends on how you intend to use your structure. There are multiple ways you can use struct Friends. You can declare a static instance of the struct, and then simply assign the address of existing strings to your firstname and lastname member pointers, e.g.:
int main (void) {
Struct Friends friend = {{Null}, {NULL]};
/* simple assignment of pointer address
* (memory at address must remain valid/unchanged)
*/
friend.firstname = argc > 1 ? argv[1] : "John";
friend.lastname = argc > 2 ? argv[2] : "Smith";
printf ("\n name: %s %s\n\n", friend.firstname, friend.lastname);
However, in most cases, you will want to create a copy of the information and store a copy of the string for the firstname and lastname members. In that case you need to allocate a new block of memory for each pointer and assign the starting address for each new block to each pointer. Here you now know what your strings are, and you simply need to allocate memory for the length of each string (+1 for the nul-terminating character) e.g.:
int main (int argc, char **argv) {
/* declare static instance of struct */
struct Friends friend = {NULL, NULL};
char *first = argc > 1 ? argv[1] : "John";
char *last = argc > 2 ? argv[2] : "Smith";
/* determine the length of each string */
size_t len_first = strlen (first);
size_t len_last = strlen (last);
/* allocate memory for each pointer in 'friend' */
friend.firstname = malloc (len_first * sizeof *friend.firstname + 1);
friend.lastname = malloc (len_last * sizeof *friend.lastname + 1);
You then need only copy each string to the address for each member:
/* copy names to new memory referenced by each pointer */
strcpy (friend.firstname, first);
strcpy (friend.lastname, last);
Finally, once you are done using the memory allocated, you must free the memory with free. note: you can only free memory that you have previously allocated with malloc or calloc. Never blindly attempt to free memory that has not been allocated that way. To free the members, all you need is:
/* free allocated memory */
free (friend.firstname);
free (friend.lastname);
A short example putting all the pieces together is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Friends {
char *firstname;
char *lastname;
};
int main (int argc, char **argv) {
/* declare static instance of struct */
struct Friends friend = {NULL, NULL};
char *first = argc > 1 ? argv[1] : "John";
char *last = argc > 2 ? argv[2] : "Smith";
/* determine the length of each string */
size_t len_first = strlen (first);
size_t len_last = strlen (last);
/* allocate memory for each pointer in 'friend' */
friend.firstname = malloc (len_first * sizeof *friend.firstname + 1);
friend.lastname = malloc (len_last * sizeof *friend.lastname + 1);
/* copy names to new memory referenced by each pointer */
strcpy (friend.firstname, first);
strcpy (friend.lastname, last);
printf ("\n name: %s %s\n\n", friend.firstname, friend.lastname);
/* free allocated memory */
free (friend.firstname);
free (friend.lastname);
return 0;
}
Always compile with warnings enabled, for example:
gcc -Wall -Wextra -o bin/struct_dyn_alloc struct_dyn_alloc.c
(if not using gcc, then your compiler will have similar options)
Anytime you dynamically allocate memory in your code, run in though a memory error checking program to insure you are not misusing the allocated blocks of memory in some way, and to confirm all memory has been freed. It is simple to do. All OS's have some type of checker. valgrind is the normal choice on Linux. For example:
$ valgrind ./bin/struct_dyn_alloc
==14805== Memcheck, a memory error detector
==14805== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==14805== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==14805== Command: ./bin/struct_dyn_alloc
==14805==
name: John Smith
==14805==
==14805== HEAP SUMMARY:
==14805== in use at exit: 0 bytes in 0 blocks
==14805== total heap usage: 2 allocs, 2 frees, 11 bytes allocated
==14805==
==14805== All heap blocks were freed -- no leaks are possible
==14805==
==14805== For counts of detected and suppressed errors, rerun with: -v
==14805== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
So with types like yours above, you have basically a two-step allocation process:
First, you allocate an object of type struct Friends, which contains space for two pointers;
Second, you allocate memory for the objects that each member of struct Friends will point to.
Quick and dirty example:
struct Friends *addFriend( const char *firstName, const char *lastName )
{
/**
* First, allocate an instance of `struct Friends`, which will contain
* enough space to store two pointers to `char`
*/
struct Friends *f = malloc( sizeof *f ); // sizeof *f == sizeof (struct Friends)
if ( f )
{
/**
* Allocate space to store a *copy* of the contents of the firstName
* parameter, assign the resulting pointer to the firstname member of
* the struct instance.
*/
f->firstname = malloc( strlen( firstName ) + 1 );
if ( f->firstname )
strcpy( f->firstname, firstName );
/**
* Do the same for lastName
*/
f->lastName = malloc( strlen( lastName ) + 1 );
if ( f->lastname )
strcpy( f->lastname, lastName );
}
return f;
}
If we call this function as
struct Friends newFriend = addFriend( "John", "Bode" );
we get something like the following in memory:
+---+ +---+ +---+---+---+---+---+
newFriend:| | --> newFriend->firstname: | | ---->|'J'|'o'|'h'|'n'| 0 |
+---+ +---+ +---+---+---+---+---+
newFriend->lastname: | | -+
+---+ | +---+---+---+---+---+
+-->|'B'|'o'|'d'|'e'| 0 |
+---+---+---+---+---+
Here's how it plays out on my system:
Item Address 00 01 02 03
---- ------- -- -- -- --
newFriend 0x7fffe6910368 10 20 50 00 ..P.
0x7fffe691036c 00 00 00 00 ....
*newFriend 0x502010 30 20 50 00 0.P.
0x502014 00 00 00 00 ....
0x502018 50 20 50 00 P.P.
0x50201c 00 00 00 00 ....
newFriend->firstname 0x502030 4a 6f 68 6e John
newFriend->lastname 0x502050 42 6f 64 65 Bode
The newFriend pointer variable lives at address 0x007fffe6910368. It points to an object of type struct Friends which lives at address 0x502010. This object is large enough to store two pointer values; newFriend->firstname lives at address 0x5020101 and points to the string "John", which lives at address 0x502030. newFriend->lastname lives at address 0x502018 and points to the string "Bode", which lives at address 0x502050.
To deallocate, you free the members before freeing the struct object:
void deleteFriend( struct Friends *f )
{
free( f->firstname );
free( f->lastname );
free( f );
}
It doesn't matter what order you free f->firstname and f->lastname with respect to each other; what matters is that you have to delete both of them before you can delete f. Freeing f won't free what f->firstname and f->lastname point to2.
Note that this all assumes I'm being given data with a known size (the firstName and lastName parameters in addFriend); I use the lengths of those input strings to determine how much space I need to allocate.
Sometimes you do not know ahead of time how much space you need to set aside. The usual approach is to allocate some initial amount of storage and to extend it as necessary using the realloc function. For example, suppose we have code to read a single line of text terminated by a newline character from an input stream. We want to be able to handle lines of any length, so we start out by allocating enough space to handle most cases, and if we need more, we double the size of the buffer as necessary:
size_t lineSize = 80; // enough for most cases
char *line = calloc( lineSize, sizeof *line );
char buffer[20]; // input buffer for reading from stream
/**
* Keep reading until end of file or error.
*/
while ( fgets( buffer, sizeof buffer, stream ) != NULL )
{
if ( strlen( line ) + strlen( buffer ) >= lineSize )
{
/**
* There isn't enough room to store the new string in the output line,
* so we double the output line's size.
*/
char *tmp = realloc( line, 2 * lineSize );
if ( tmp )
{
line = tmp;
lineSize *= 2;
}
else
{
/**
* realloc call failed, handle as appropriate. For this
* example, we break out of the loop immediately
*/
fprintf( stderr, "realloc error, breaking out of loop\n" );
break;
}
}
strcat( line, buffer );
/**
* If we see a newline in the last input operation, break out of the
* loop.
*/
if ( strchr( buffer, '\n' ) )
break;
}
1. The address of the first element of a struct is the same as the address of the whole struct object; C doesn't store any kind of metadata before the first struct member.
2. Note that you can only call free on an object that was allocated with malloc, calloc, or realloc; you would not call free on a pointer that points to a string literal or another array.
If i understood your problem correctly, you want to see the memory allocated for firstname and lastname based on your requirement of the future storage.
I'm afraid, that is not possible.
When you got a variable of type struct Friends, say struct Friends F;, F.firstname and F.lastname will be pointers but they will not be pointing to any valid memory. You need to perform the allocation for F.firstname and F.lastname separately. Something like
F.firstname = malloc(32);
F.lastname = malloc(32); //perform NULL check too
and then you can actually make use of F.firstname and F.lastname
Everywhere I look they allocate the memory, before they know how much they will fill the structure with.
If I understood properly you are asking how we can allocate memory before they know how much space we gonna use.
Consider the following structure:
struct foo
{
char bar;
char foobar;
};
struct foo *temp = (struct foo *) malloc(sizeof(struct foo));
Here 2 * 1 = 2 bytes will be allocated dynamically whether you store something in bar and foobar variables or not.
If you don't store anything then the variable (memory location) contains grabage value.
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.
I have an unsigned char array of size 64 that i want to change value of at runtime, however all my attemps have failed miserably, what am I doing wrong?
int main() {
unsigned char buffer[64]={0xef,0xaa,0x03,0x05,0x05,0x06,0x07,0x08,......};
buffer = {0x01,0x04,0xa0,0xb0,0xde,0x00,.....}; //fails
return 0;
}
EDIT: I don't want to fill with zero's the array buffer, I want to place a new value
Another solution would be the use of almighty memcpy() and C99 compound literals:
memcpy(array, (int []){ 0x00, 0x01, 0x02 }, sizeof array);
Believe it or not, this works.
for (int i = 0; i < 64; ++i) buffer[i] = 0x00;
or in C++ (11 or later), you can use std::fill_n or std::generate_n
std::fill_n(buffer, 64, 0x00);
or
for (auto &b : buffer) b = 0x00;
From your comment I see you do not want to access elements of the array. If not, then here is another solution to your problem.
You could declare the buffer on the memory pool. Hence,
unsigned char *buffer = malloc( sizeof( unsigned char ) * 64 );
... and then if you ever wanted to replace all of the elements of the array (as you have attempted to do using the array initialization syntax), it would be done as follows:
memset( buffer, 0x00, sizeof( unsigned char ) * 64 ); // To replace buffer = { 0x00, ..., 0x00 };.
memset( buffer, 0, sizeof( unsigned char ) * 64 ); // To replace buffer = '0...0';.
Legacy:
If you wanted to use an array declared on the stack then you would need to mutate it one element at a time using the square brackets [ ]. It would be done as follows:
for ( int i = 0; i < 64; i++ ) {
buffer[ i ] = val; // where "val" is some value.
}
Use std::memset:
memset(buffer, 0, sizeof(buffer));
There's also bzero, but it's a legacy function, so it shouldn't be used in new development.
You can change the values of the element in two ways :
unsigned char buffer[64]={0xef,0xaa,0x03,0x05,0x05,0x06,0x07,0x08,......};
buffer[0] = 0;
buffer[1] = 15;
// etc ...
// C++11 for-loop range works fine to :
for ( auto &c : buffer )
c = 0;
Or after that, you can use function like : memset, std::fill_n :
memset( buffer, 0, sizeof(buffer) );
std::fill_n( buffer, 64, 0x00 );
You could use snprintf:
#include <stdio.h>
int main() {
unsigned char buffer[64]={0};
snprintf(buffer, 64, "Hello World!\x0D\x0A");
printf(buffer);
}
Output:
$ ./a.out | hexdump -C
00000000 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 0d 0a |Hello World!..|
0000000e
Initialization and assignment are two different operations, despite similarity in the syntax.
int x[4] = { 1, 2, 3, 4}; // initialization
x = { 1, 2, 3, 4}; // assignment
Additionally, raw arrays in C and C++ behave strangely and in particular there's a special rule that says that they are not assignable:
int x[4];
int y[4];
y = x; // error, arrays are not assignable
So even if you create an array temporary object you cannot simply copy that into another array object using the assignment operator.
Instead, if you are set on using raw arrays, you have to set each array element individually, using memcpy, fill, etc.
A better solution is to use C++ and a type other than raw arrays which does allow assignment, such as std::array<unsigned char, 64>:
std::array<unsigned char, 64> buffer = {0xef,0xaa,0x03,0x05,0x05,0x06,0x07,0x08};
buffer = {}; // zeros out the array
The std::array template just generally behaves consistently like a normal object whereas raw arrays in C and C++ have all these very strange behaviors and special cases in the language specs. You should avoid using raw arrays.
Unfortunately C does not have any alternative to raw arrays.
Since that are some compiler issues, try a simple usage of memcpy().
#include <string.h>
int main() {
unsigned char bufferTo[ 64]={0xef,0xaa,0x03,0x05,0x05,0x06,0x07,0x08,......};
unsigned char bufferFrom[64]={0x01,0x04,0xa0,0xb0,0xde,0x00,.....};
memcpy(bufferTo, bufferFrom, 64);
return 0;
}