C strcpy() to a Pointer? How does this work? - c

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.

Related

how save pointer address after free the pointer in c

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.

What is real meaning behind this easy printf output in c?

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.

Why cannot be pointer free() after pointing to string literal

There are some related discussions about my problem but there are no clearly explanations about my problem.
I thought that I must free() whatever I malloc(), no matter when or where but I have to do it, to prevent a memory leak.
So i have the following program:
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int *ptr;
ptr = malloc(256);
if (ptr == NULL) {
printf("Out of memory\n");
return 1;
}
*ptr = 10;
printf("The value of PTR is:\t%d\n",*ptr);
free(ptr);
return 0;
}
I have a pointer and I dynamically allocated some memory (256), then I checked for NULL letter I free() it.
Until here everything is OK: to the pointer was dynamically allocated some memory and then I free() it.
Now i will use a char pointer this time and after i will dynamically allocated some memory (256), i will point that pointer to a string literal, lets say MICHI:
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
char *ptr;
ptr = malloc(256);
if (ptr == NULL) {
printf("Out of memory\n");
return 1;
}
ptr = "michi";
printf("%s",ptr);
free(ptr);
return 0;
}
Here I am doing something wrong because if i try to free() it, well it will not work because it happens that i'm going to free a non-heap object.
So i'm lost in here, because i thought that everything you malloc() you have to free() it.
What exactly make that pointer, after points to a string literal, to not need to be free()ed
ptr = malloc(256);
...
ptr = "michi";
printf("%s",ptr);
free(ptr);
As you allocate memory to ptr and then you make it point to string literal. Thus pointer ptr no longer points to memory allocated by malloc.
And to free memory not allocated by malloc or similar functions cause error in program.
Do this instead:
strcpy(ptr,"michi");
In the first program you allocated memory
ptr = malloc(256);
and initialized its first sizeof( int ) bytes with integer value 10.
*ptr = 10;
The pointer itself was not changed. So in this statement
free(ptr);
pointer ptr points to the memory that was allocated using malloc.
In the second program you allocated memory the same way as in the first program
ptr = malloc(256);
But then you reassigned the pointer itself with the address of the first character of string literal "michi"
ptr = "michi";
Compare the left sides of this assignment
*ptr = 10;
and of this assignment
ptr = "michi";
As you see they are different. In the first case you are changing the allocated memory while in the second case you are changing the pointer itself.
Thus in this statement
free(ptr);
pointer ptr does not point to the memory that was previously allocated. It points to the memory occupied by the string literal that was not allocated using malloc.
Thus this statement is wrong and the program has a memory leak because the previous memory that was allocated using malloc was not freed,
Because constant literals are stored in a way for the lifetime of the program, in a read-only region of memory in most of the platforms.
When you use free you are trying to free the memory allocated, not the pointer itself, that's why it's not gonna work if you try to do that in a read-only region of memory
When you reassign your pointer you're losing track of the allocated memory and therefore creating a memory leak.
The memory leak is created because you first allocated the memory and assign it to your pointer, when you've a pointer pointing to it you can easily free that memory, but when you don't have any more reference to that memory you can't.
That's what's happening, when assign the literal to the pointer there's no more reference to that address, it was allocated but it's not reachable anymore, in this way you can't free the memory.
The problem is that you have lost the pointer the second you assigned another value to it:
ptr = malloc(256);
if (ptr == NULL) {
printf("Out of memory\n");
return 1;
}
// here you should free your memory
ptr = "michi";
printf("%s",ptr);
// this fails, because ptr now points to the const static string "michi" you have coded yourself. The assignment didn't copy it, just changed what ptr points to.
free(ptr);
Try this.
#include <stdio.h>
int main(void)
{
char *str:
str = (char*)malloc(sizeof(str) * 4);
printf("Addr of str before: %p\n", str);
str = "Joe";
printf("Addr of str after: %p\n",str);
return(0);
}
/* you will get the following addresses:
Addr of str before: 0x51fc040
Addr of str after: 0x4006f0
this is becuase you changed where str points to. 0x51fc040 is memory allocated using malloc and 0x4006f0 is the memory Adress of the string literal "Joe".
I would advice the following...*/
#include <stdio.h>
int main(void)
{
char *str;
str = (char*)malloc(sizeof(str) * 4);
printf("Addr of str before: %p\n", str);
str =strncpy(str, "Joe", 4);
printf("Addr of str after: %p\n",str);
free(str);
return (0);
}
/* you will get the following addresses:
Addr of str before: 0x51fc040
Addr of str after: 0x51fc040
This is because strncpy copies the string literal to the memory dynamically allocated. and it is safer than stcpy, since it prevents buffer overflow

What does memcpy do exactly in this program?

I am writing a program where the input will be taken from stdin. The first input will be an integer which says the number of strings to be read from stdin.
I just read the string character-by-character into a dynamically allocated memory and displays it once the string ends.
But when the string is larger than allocated size, I am reallocating the memory using realloc. But even if I use memcpy, the program works. Is it undefined behavior to not use memcpy? But the example Using Realloc in C does not use memcpy. So which one is the correct way to do it? And is my program shown below correct?
/* ss.c
* Gets number of input strings to be read from the stdin and displays them.
* Realloc dynamically allocated memory to get strings from stdin depending on
* the string length.
*/
#include <stdio.h>
#include <stdlib.h>
int display_mem_alloc_error();
enum {
CHUNK_SIZE = 31,
};
int display_mem_alloc_error() {
fprintf(stderr, "\nError allocating memory");
exit(1);
}
int main(int argc, char **argv) {
int numStr; //number of input strings
int curSize = CHUNK_SIZE; //currently allocated chunk size
int i = 0; //counter
int len = 0; //length of the current string
int c; //will contain a character
char *str = NULL; //will contain the input string
char *str_cp = NULL; //will point to str
char *str_tmp = NULL; //used for realloc
str = malloc(sizeof(*str) * CHUNK_SIZE);
if (str == NULL) {
display_mem_alloc_error();
}
str_cp = str; //store the reference to the allocated memory
scanf("%d\n", &numStr); //get the number of input strings
while (i != numStr) {
if (i >= 1) { //reset
str = str_cp;
len = 0;
}
c = getchar();
while (c != '\n' && c != '\r') {
*str = (char *) c;
printf("\nlen: %d -> *str: %c", len, *str);
str = str + 1;
len = len + 1;
*str = '\0';
c = getchar();
if (curSize/len == 1) {
curSize = curSize + CHUNK_SIZE;
str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
if (str_tmp == NULL) {
display_mem_alloc_error();
}
memcpy(str_tmp, str_cp, curSize); // NB: seems to work without memcpy
printf("\nstr_tmp: %d", str_tmp);
printf("\nstr: %d", str);
printf("\nstr_cp: %d\n", str_cp);
}
}
i = i + 1;
printf("\nEntered string: %s\n", str_cp);
}
return 0;
}
/* -----------------
//input-output
gcc -o ss ss.c
./ss < in.txt
// in.txt
1
abcdefghijklmnopqrstuvwxyzabcdefghij
// output
// [..snip..]
Entered string:
abcdefghijklmnopqrstuvwxyzabcdefghij
-------------------- */
Thanks.
Your program is not quite correct. You need to remove the call to memcpy to avoid an occasional, hard to diagnose bug.
From the realloc man page
The realloc() function changes the size of the memory block pointed to
by ptr to size bytes. The contents will be unchanged in the range
from the start of the region up to the minimum of the old and new
sizes
So, you don't need to call memcpy after realloc. In fact, doing so is wrong because your previous heap cell may have been freed inside the realloc call. If it was freed, it now points to memory with unpredictable content.
C11 standard (PDF), section 7.22.3.4 paragraph 2:
The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. Any bytes in the new object beyond the size of the old object have indeterminate values.
So in short, the memcpy is unnecessary and indeed wrong. Wrong for two reasons:
If realloc has freed your previous memory, then you are accessing memory that is not yours.
If realloc has just enlarged your previous memory, you are giving memcpy two pointers that point to the same area. memcpy has a restrict qualifier on both its input pointers which means it is undefined behavior if they point to the same object. (Side note: memmove doesn't have this restriction)
Realloc enlarge the memory size where reserved for your string. If it is possible to enlarge it without moving the datas, those will stay in place. If it cannot, it malloc a lager memory plage, and memcpy itself the data contained in the previous memory plage.
In short, it is normal that you dont have to call memcpy after realloc.
From the man page:
The realloc() function tries to change the size of the allocation pointed
to by ptr to size, and returns ptr. If there is not enough room to
enlarge the memory allocation pointed to by ptr, realloc() creates a new
allocation, copies as much of the old data pointed to by ptr as will fit
to the new allocation, frees the old allocation, and returns a pointer to
the allocated memory. If ptr is NULL, realloc() is identical to a call
to malloc() for size bytes. If size is zero and ptr is not NULL, a new,
minimum sized object is allocated and the original object is freed. When
extending a region allocated with calloc(3), realloc(3) does not guaran-
tee that the additional memory is also zero-filled.

Using a pointer in a struct

While I was inputting "stuList[1].name", an error occurred and the program crashed. How do I fix this?
#include <stdio.h>
#include <conio.h>
typedef struct student
{
int id;
char *name;
float percentage;
} student;
int main()
{
student stuList[3];
stuList[0].name = "vermidonhapic";
stuList[2].name = "didiervermiyer";
scanf("%s\n",&stuList[1].name);
printf(" name is: %s \n", stuList[0].name);
printf(" name is: %s \n", stuList[2].name);
printf(" name is: %s \n", stuList[1].name);
system("PAUSE");
}
In this command: scanf("%s\n",&stuList[1].name);
You are scanning string from input without actually allocating the required memory.
This results in trying to write the data in an unkown address, which is not yours, which results in a segmentation fault.
To fix it, first allocate memory: stuList[1].name = malloc(MAX_LENGTH);, and only after: scan the string from stdin.
name is just a pointer that isn't pointing to memory you own, so writing through it will corrupt memory. You need to allocate some memory on it with malloc(), or make it an array rather than a pointer.
stuList[1].name is an invalid pointer as it has not been initialized to point to a valid object.
You should dynamically allocate memory (through malloc function) for stuList[1].name so scanf could write to an allocated object.
stuList[1].name = malloc(size_enough_to_store_your_string);
Moreover, stuList[1].name is a pointer to char so you should use stuList[1].name and not &stuList[1].name (pointer to a pointer to char) in your scanf function call.
You forgot to allocate memory for stuList[1].name. You need to allocate it from the heap with malloc or stack allocate it.
stuList[1].name = malloc(MAX_NAME_LENGTH);//heap allocation
//use stuList[1].name
free(stuList[1].name);
char buffer[MAX_NAME_LENGTH];//stack allocation
stuList[1].name = buffer;
I've omitted all error checking, protection against over-running buffers etc.
Since stuList[1].name is a pointer, you are incorrect in taking its address in your scanf.

Resources