When I try compiling the following C code, i get a bus error.
I'm guessing it has something to do with the way I have called memcpy, however I cant figure it out.
Any help would be greatly appreciated!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *p = (char*)malloc(sizeof(char)*11);
// Assign some value to p
p = "hello";
char *name = (char*)malloc(sizeof(char)*11);
// Assign some value to name
name = "Bye";
memcpy (p,name,sizeof(char)*10); // Problem begins here
return 0;
}
Here p points to a string literal after your assignment, NOT to your allocated memory!
Then you try to write into that memory with memcpy.
Many C compilers allocate string literals in read-only memory, hence the bus error.
To fix your problem, you should copy the characters h, e, l, l, and o into the space you allocated for p in the first line of main, using strncpy. This keeps p pointing to the memory you allocated yourself; the later memcpy will be fine (provided you don't overflow your buffer of course).
Note that in general when you assign to a string variable directly you are making the variable point to a different memory address. In your code you have allocated space for a couple of strings but when you assign string literals to the variables, you are changing the location to which they point, causing a memory leak.
In your code, that p = "hello" the "hello" return a pointer which point to a string hello and the hello can't be change. You use p = "hello" means make p point to this string too. So when you try to change it, you will get an error.
The right way is like follows:
char a[] = "hello"; or
char *a = malloc(sizeof(char)*11); /*cast is not good*/
strcpy (a, "hello");
BTW, use malloc had better NOT using cast like (char *) or (int *).
Related
I'm not quite sure I get how malloc works exactly.
#include <stdio.h>
#include <stdlib.h>
int main() {
char * string = (char*) malloc(sizeof(char));
string = "abc";
int * test = (int*) malloc(1 * sizeof(int));
*(test) = 5;
*(test + 1) = 6;
}
I expected this to output an error since the value I appoint to string is bigger than just one char yet it seems to compile just fine.
I have a few questions:
Where would 'string' be saved now? is it on memory spaces on the heap after the one space I allocated ?
Why is does the char let me appoint directly and the int only via pointer?
I'm really not sure what I'm doing here
This code
string = "abc";
assigns the address of the string constant "abc" to the string variable, which is a char *. The address of the memory returned from your malloc() call - which was in string - gets overwritten and lost.
In addition to the other answers:
You probably want this:
char *string = (char*) malloc(sizeof(char) * 100); // allocate space for 100 chars
strcpy(string, "abc"); // copy the "abc" into the memoory location pointer by string
instead of this:
char *string = (char*) malloc(sizeof(char)); // << this allocates only a single char
string = "abc";
And
*(test) = 5;
*(test + 1) = 6;
is better written as:
test[0] = 5;
test[1] = 6;
which is strictly equivalent, it's just a matter of readability.
Allocating too few memory:
If you allocate memory for only 1 char as here:
char *string = (char*) malloc(sizeof(char)); // allocate space 1 char
strcpy(string, "abc"); // copy the "abc" into the memoory location pointer by string
then your program will still compile fine, but at runtime the string will be copied partly to non allocated memory, which results in undefined behaviour (google "undefined behaviour").
Where would 'string' be saved now?
char * string = (char*) malloc(sizeof(char));
string = "abc";
string now points to "abc" (a literal string) - the initial dynamic allocation (in the heap) has been lost track and you have a memory leak.
I will give you a real-life example.
Suppose Mr. A lives at the address "abc". Now, some Mr. B starts living at some address "xyz". Soon, Mr. B address "xyz" is renamed to "abc". Now, if you go to the address "abc", you will meet Mr. B, not Mr. A. But, this don't mean that Mr. A place is demolished. It simply means that Mr. A's living area now has no reachable address and is lost.
Similarly, the memory you malloc'ed to string and then re-assigned the string to "abc", means, string earlier had an address to the malloc'ed memory. Later, your "abc" is written to some memory and the address to that memory is stored in string. Thus, losing the malloc'ed memory forever which is called Memory Leak.
The compiler will not prevent you to do something that is allowed - however you're likely to get a warning for the 1) since string is assigned and not used before being re-assigned (provided that the compiler is requested to output the relevant warnings).
As for 2), you call a function which happens to be malloc, with an argument that happens to be too small for the usage you want to do with the pointer returned by malloc, but since the syntax is correct, the compiler doesn't complain.
Answer to
1) string points to "abc" and the previous value from malloc is lost
2) you could do test[0] = 5; as well.
The behavior for 2) is undefined behavior (access an array out of bounds).
At first there was allocated dynamically memory with the requested size of one character.
char * string = (char*) malloc(sizeof(char));
And then the pointer was reassigned with the address of the first character of the string literal "abc".
string = "abc";
As result the address of the dynamically allocated memory was lost and there is a memory leak in the program.
If the program would written in C++ then this statement
string = "abc";
could arise a compiler diagnostic message because string literals in C++ have types of constant character arrays and the pointer string shuld be declared like
const char *string;
As for the string literal then they have static storage duration and are allocated before main gets the control. Usually all string literals are places in the so-called string literal pool.
Instead of this statement
string = "abc";
you could write
strcpy( string, "abc" );
In this case the program has undefined behavior. However it can continue to work successfully due to the feature that usually the function malloc allocates minimum memory extent equal to the value of the paragraph that is equal to 16 bytes.
Here are the codes, it's C code. And please explain return value of ="string"
char * p = (char*) malloc(sizeof(char) * 100);
p = "hello";
*(p+1) = '1';
printf("%s", p);
free(p);
Notice that p = "hello"; does not copy any string, but just sets the pointer p to become the address of the 6 bytes literal string "hello". To copy a string use strncpy or strcpy (read strncpy(3) ...) but be scared of buffer overflows.
So you do
char * p = malloc(100);
which allocates a memory zone capable of holding 100 bytes. Let's pretend that malloc succeeded (read malloc(3)...) and returned the address 0x123456 for example (often, that concrete address is not reproducible from one run to the next, e.g. because of ASLR).
Then you assign p = "hello"; so you forgot the address 0x123456 (you've got now a memory leak), and you put in p the address of the 6 bytes literal string "hello" (let's imagine it is 0x2468a).
Later the machine executes the code for *(p+1) = '1'; so you are trying to replace the e character (at address 0x2468b) inside literal "hello" by 1. You get a segmentation violation (or some other undefined behavior), since that literal string sits in constant read only memory (e.g. the text segment of your executable, at least on Linux).
A better code might be:
#define MY_BUFFER_LEN 100
char *p = malloc(MY_BUFFER_LEN);
if (!p) { perror("malloc for p"); exit(EXIT_FAILURE); };
strncpy(p, "hello", MY_BUFFER_LEN); /// you could do strcpy(p, "hello")
*(p+1) = '1';
printf("%s", p);
free(p);
and if you are lucky (no memory failure) that would much later output h1llo (the output will happen only when stdout becomes flushed since it is buffered, e.g. by some later call to fflush). So don't forget to call
fflush(NULL);
after the previous code chunk. Read perror(3), fflush(3).
A generic advice is to read documentation of every function that you are using (even printf(3) ...).
Regarding printf and related functions, since stdout is often line buffered, in practice I strongly recommend to end every format control string with \n -e.g. printf("%s\n", p); in your code; when you don't do that (there are some cases where you don't want to...) think twice and perhaps comment your code.
Don't forget to compile with all warnings and debug info (e.g. gcc -Wall -Wextra -g) then learn how to use the debugger (e.g. gdb)
Your code doesn't do what you think it does.
"hello" is behind the scenes a pointer to a static array of six chars, most likely write protected.
When you assign it to p, the pointer that malloc returned is lost, instead p now contains a pointer to that static array of six chars.
The assigment to p+1 may crash, or may not crash, but whatever it does, it is undefined behaviour and will cause trouble.
free (p) tries to free a static array of six chars. That isn't going to work. Again, undefined behaviour, and an immediate crash if you are lucky.
There are problems in nearly each line:
1) In the first line you are assigning to p the address of newly allocated memory. which is OK
2) In the next line you overwrite it with an address of some static string. Which is bad, since the allocated memory is "lost", thus causing memory leak.
3) In the third line you are trying to overwrite something in the static string location, which might be read only, which is bad.
4) In the last line you are trying to free the memory at the string's location, which is memory violation.
You need to understand what pointers are.
In C, there is no variable that can store a string. Instead the strings are stored in arrays of chars. In order to be able to handle such an array, you use a variable (called pointer) that stores the memory address of the first element of the array. Also, strings have a special character (the nul character) the indicate where they end, but that's not relevant here.
In the code you posted, you allocate memory to store 100 chars (this is usually 100 bytes) and get a pointer to the first element of this memory region, called p (for further reading: Do I cast the result of malloc?).
Whenever you use a string literal, some memory gets allocated and it gets stored in that memory region. When you assign it to p, p now points to the first element of the new memory region, that stores the string (so you've lost the memory allocated you malloc -> memory leak). Now, you try to modify the string pointed at by p. This won't work, as the string literals are stored as constant strings. And after that, you try to free the memory of this string, which is not possible. All of these mistakes generate runtime errors and are not very easy to detect and fix. In order to be able to achieve what you want, use a function like strcpy to copy the string from the read-only memory region to your pointer:
strcpy(p, "string");
Strings in C are arrays, and you can't use = to assign values to arrays, only to indexed elements of arrays. For copying string data, use strcpy() or strncpy(). Your code could look like:
char *p = (char*) malloc(sizeof(char) * 100);
strcpy(p, "hello");
*(p+1) = '1';
printf("%s", p);
free(p);
Try that. The difference is that p = "hello" will set the pointer p to point to the constant string "hello", overwriting the pointer to the 100-byte memory block you just allocated. The free(p); call below will fail because you're passing a pointer not returned by an allocation function, even if the system you're using doesn't give a write fault on attempting to modify constant data.
If you ever do need to point a pointer at a constant string (it happens), be sure you declare the pointer as const char *. This is required in C++. I don't know if it's required in newer versions of C, but it's a Real Good Idea in any case.
1) In C it is incorrect cast the return of malloc() (C++, okay to cast)
2) Once allocated memory, assigning a value to p is not done by =.
strcpy(p, "hello"); is better.
3) Once assigned correctly, using strcpy(), *(p+1) = '1' is the same as p[1] = '1', and will result in "h1llo".
By the way, using the line *(p+1) = '1' AFTER using p = "hello" to assign the value hello (instead of strcpy()) will cause problems, as described by #gnasher, #Basile and others.
I have simple code,
#include "stdafx.h"
#include <malloc.h>
int main()
{
char *p = (char*) malloc(10);
p = "Hello";
free(p);
return 0;
}
This code is giving run time exception while terminating. Below is error snippiest,
Microsoft Visual C++ Debug Library
Debug Assertion Failed!
Program: ...\my documents\visual studio 2010\Projects\samC\Debug\samC.exe
File: f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c
Line: 1322
Expression: _CrtIsValidHeapPointer(pUserData)
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
Abort Retry Ignore
p = "Hello"; makes p point to a string literal and discards the previously assigned value. You can't free a string literal. You can't modify it.
If you want p to hold that string, just use
char* p = "Hello";
or
char p[] = "Hello";
if you plan on modifying it.
Neither requires free.
This is how you write a string in the memory allocated by malloc to a char pointer.
strcpy(p, "Hello");
Replace the line
p = "Hello";
with the strcpy one & your program will work fine.
You also need to
#include <string.h>
malloc returns a pointer to allocated memory. Say the address is 95000 (just a random number I pulled out).
So after the malloc - p will hold the address 95000
The p containing 95000 is the memory address which needs to be passed to free when you are done with the memory.
However, the next line p = "Hello"; puts the address of the string literal "Hello" (which say exists at address 25000) into p.
So when you execute free(p) you are trying to free 25000 which wasn't not allocated by malloc.
OTOH, when you strcpy, you copy the string "Hello" into the address starting at p (i.e. 95000). p remains 95000 after the strcpy.
And free(p) frees the right memory.
You can also avoid the malloc and use
char *p = "Hello";
However, in this method, you cannot modify the string.
i.e. if after this you do *p = 'B' to change the string to Bello, it becomes an undefined operation. This is not the case in the malloc way.
If instead, you use
char p[] = "Hello";
or
char p[10] = "Hello";
you get a modifiable string which need not be freed.
p = "Hello";
free(p);
Since Hello is statically allocated, you cannot free it. I'm not sure why you allocate some memory just to throw the pointer away by changing it to another pointer, but that has no effect. If you do this:
int i = 1;
i = 2;
i has no memory that it once held a 1, it holds a 2 now. Similarly, p has no memory that it once held a pointer to some memory you allocated. It holds a pointer to an immutable constant now.
this is a nice one.
the char sequence "hello" is constant and therefore placed niether on the heap nor the stack, but in the .bss/.data segment. when you do p="hello" you make p point to the address of the string hello in that segment instead of the memory you alocated on the heap using malloc. when you go to free p it tries to free the memory in the .bss/.data segment, and naturally fails.
what you probably want is something like strcpy(p,"hello"); which goes over every char in "hello" and places it in the memory pointed to by p. essentially creating a copy of the string "hello" at memory address p.
If you want to copy the contents of the string "Hello" to the memory you allocated, you need to use strcpy:
strcpy(p, "Hello");
The line
p = "Hello";
assigns the address of the string literal "Hello" to the pointer p, overwriting the pointer value that was returned from malloc, hence the crash when you call free.
I have this code:
#define ABC "abc"
void main()
{
char *s = malloc(sizeof(char)*3);
printf("%p ", s);
s = ABC;
printf("%p ", s);
free(s);
}
This is the output:
0x8927008 0x8048574 Segmentation fault (core dumped)
As you can see, the address of string s changes after assignment (I think this is why free() gives segfault).
Can anyone explain me why and how this happens?
Thank you!
The line
s = ABC;
changes s to point to a different string which may well be in read-only memory. Attempting to free such memory results in undefined behaviour. A crash is likely.
I think you wanted
strcpy(s, ABC);
instead. This would copy the char array "abc" into s. Note that this will cause a further bug - s is too short and doesn't have space for the nul terminator at the end of ABC. Change you allocation to 4 bytes to fix this
char *s = malloc(4);
or use
char *s = malloc(sizeof(ABC));
if ABC is the max length you want to store.
void main() UB: main returns int
printf("%p", s) UB: calling a function accepting a variable number of arguments without a prototype in scope; UB: using a value of type char* where a value of type void* is expected.
free(s) UB: s is not the result of a malloc()
UB is Undefined Behaviour.
After
char *s = malloc(sizeof(char)*3);
s points to the memory allocated by malloc.
The line
s = ABC;
will change to
s = "abc";
after the prepossessing. Now this step makes s point to the string literal "abc" in the read-only area. Note that this also leaks the malloced memory.
Now since s is pointing to a non-malloced read-only memory, free it is a undefined behavior.
If you wanted to copy the string "abc" into memory pointed to by s you need to use strcpy as:
strcpy(s, ABC);
but note that to accommodate "abc", s must be at least 4 characters long, to accommodate the NUL character as well.
Change the line: char *s = malloc(sizeof(char)*3);
to
char *s = (char *)malloc(sizeof(char)*3);
This clears up warnings many compilers warn about.
More than that I recommend that you make your code more flexible depending on what you do. If for some reason you change ABC to "ABCD", you will not have allocated enough space for all the characters.
Also, the string "ABC" has actually 4 characters (since there is a null at the end that terminates the strings). You'll see issues without that extra terminator.
This code produces "p = hello world":
#include "stdio.h"
#include "string.h"
int main(){
char *p;
p="hello world";
printf("p is %s \n",p);
return 0;
}
But this code produces a segmentation fault:
#include "stdio.h"
#include "string.h"
int main() {
char *p;
strcpy(p,"hello");
printf("p is %s \n",p);
return 0;
}
and this code produces "p = hello"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int main() {
char *p;
p=(char*)malloc (10);
strcpy(p,"hello");
printf("p is %s \n",p);
return 0;
}
In the case where p="hello world"; (1st case at the time of this edit), p is being initialized to point to a read-only memory region which contains the string "hello world" (string literal). This read-only memory region is created at compile time.
In the case that causes the segmentation fault (2nd case at the time of this edit), p is uninitialized and copying anything to it will produce unpredictable results because the location in memory that p is pointing to is not specified by the code.
Before you can copy a string to p, you must specify the memory that p is pointing to.
You can allocate this memory on the stack
char buf[BUFSIZ] = ""; /* local variable */
on the heap
char *buf = malloc(BUFSIZ); /* don't forget to free */
or in the __DATA segment.
static char buf[BUFSIZ] = ""; /* global variable */
You can then initialize p to point at the memory buffer.
char *p = buf;
This is similar in concept to initializing p to point to the string literal in read-only memory. Unlike the case where p points to the string literal, you can now copy a string to the character pointer as it does not point to read-only memory.
Note: I intentionally created a separate buffer and initialized p to point to it to help make my point.
The reason is that when you declare a pointer, it doesn't actually point to anything useful. strcpy requires a block of memory for the string to be copied into. It will not do this for you automatically.
From the documentation (emphasis mine):
Copies the C string pointed by source
into the array pointed by destination,
including the terminating null
character.
To avoid overflows, the size of the
array pointed by destination shall be
long enough to contain the same C
string as source (including the
terminating null character), and
should not overlap in memory with
source.
You need to make this true, as it is a precondition of the function.
Also, in the parameters section:
destination
Pointer to the destination array where the content is to be copied.
You need to make sure destination is a pointer to an array.
There is no free lunch - you need to grab & manage memory. If you just assume that because you have access to a pointer memory should be there then you'll run into unspecified behavior (segfault likely).
Because in the first example the pointer p contains some random garbage that happens to be on the stack at the time, might be zero, might be anything else, so it points to ... nobody knows where, your code segment, for example. The OS does the right thing and tells you that you are breaking the rules and trying to write to memory that doesn't belong to you. Read the fine description of segmentation faults here.
If you absolutely want to avoid dynamic memory allocation and you know the size of the source string at compile time you can grab appropriate stack space like this:
char buffer[6]; /* strlen( "hello" ) + 1 for zero terminator */
strcpy( buffer, "hello" );
But that is a dangerous road leading to buffer overruns.
Notice what the two working examples have in common: they have a p = line that assigns something to p. The non-working example does not do this.
Consider this line (from the first example):
p = "hello world";
Although it might look like it's "copying a string to a char pointer", it's not. It's copying the location of a string to a pointer-to-char. That's what a pointer-to-char like p stores - the location of a contiguous block of chars.
Similarly, consider this line from the third example:
p = malloc(10);
This is also copying a location - it's copying the location of a block of 10 unintialised chars into p.
strcpy(dest, source) copies characters from the location given by source to the location given by dest. It should be clear that if you never set p to a valid location, then strcpy(p, "hello") can't do anything sensible - in your second example, p is an essentially random location, and you then ask strcpy() to copy something to that location.
There are two distinct parts to memory copying. The first is the memory occupied by the item you want to copy (which you create in your example using the malloc() function), and the second is a pointer to that block of memory (which you call p). These two entities must be set up for the destination too, before you can do a copy. In your first example that fails, you have not set up the memory block for the destination (but it has been set for the source implicitly when you declare the string hello).
Yes its annoying. You can use strdup to shorten it:
char *p = strdup("hello");
printf("p is %s \n",p);