I want to write a function that can copy the content of a c-string to another c-string.
#include <stdio.h>
#include <string.h>
void copy(char*,char*);
int main(){
char* string = "hello";
char* destination;
copy(destination,string);
printf("Source: %s\nDestination: %s",string,destination);
system("pause");
return 0;
}
void copy(char* dest, char* src){
dest = malloc(strlen(src)*sizeof(char)); //Crashes
while (*src){
*dest++ = *src++;
}
}
Allocating the memory inside the function makes the program crash while allocating the memory before the function call works:
char* destination = malloc(strlen(string)*sizeof(char)); //works
The primary issue, that has been explained in several different ways, has to do with how you pass dest to copy(). When you pass a pointer to a function, e.g.:
void copy(char* dest, char* src) {
The function receives a copy of the pointer, which will point to the same address, but will have a different address of its own. So when you pass char *dest, the copy() function receives a copy of the dest pointer. When you then allocate dest in copy(), the caller main() has no idea what the address for dest is in copy() and no way of accessing the memory as returned by dest = malloc(strlen(src)*sizeof(char)); in copy().
Whenever you allocate memory in a function, if you are not returning the address for the newly allocated block of memory, you must pass the address of the pointer to the function (not a copy of the pointer). That way when you call malloc, you are assigning the return of malloc (the start address for the new block of memory) as the value of the pointer at the same address as in main().
If you remember nothing else, remember that rule: If you are allocating memory for a pointer you pass to the function, you must either (1) return the new address to the caller; or (2) pass the address of the pointer to the function for allocation.
Here is another example along similar lines with a few different approaches:
#include <stdio.h>
#include <stdlib.h>
void copy (char **dest, char *src);
int main (int argc, char **argv) {
char *str = argc > 1 ? argv[1] :
"A quick brown fox jumps over the lazy dog.";
char *dest = NULL;
copy (&dest, str);
printf ("\n str : %s\n dest : %s\n\n", str, dest);
free (dest); /* free allocated memory */
return 0;
}
void copy (char **dest, char *src)
{
if (!src) { /* validate src string */
fprintf (stderr, "%s() error: invalid string 'src'.\n",
__func__);
return;
}
size_t len = 0;
char *p = src;
for (;*p; p++, len++) {} /* strlen */
/* allocate and validate -- every time */
if (!(*dest = malloc (len * sizeof **dest + 1))) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n",
__func__);
exit (EXIT_FAILURE);
}
p = *dest; /* copy src to dest */
for (; *src; src++) *p++ = *src;
*p = 0; /* null-terminate */
}
Output
$ ./bin/copystr
str : A quick brown fox jumps over the lazy dog.
dest : A quick brown fox jumps over the lazy dog.
Note: if you are not using gcc then change __func__ to the function name.
In your main() function you are declaring a variable destination of type char * without initializing it. You then pass destination as an argument to your copy() function. It's important to understand what data is being passed to copy(). In this case, since destination has not been initialized, we don't know what is being passed to copy(). This is fine when you malloc() before the function call because, in that scenario, destination has been initialized. In particular, its value is some address in the heap that was returned by malloc().
As others have noted, you should also be careful to allocate 1 byte more than the src string length in order to allow space for the null-terminator.
The problem is that copy takes to addresses - the current value of destination and the value of source.
Then it overwrites the current value of destination with the result of malloc.
The copy then occurs, and the malloced memory gets lost.
Either return the value of destination from copy, rather than pass it in.
or use char ** and *.
char * copy( char* src){
char * dest = malloc( (1+strlen(src))*sizeof(char)); //Crashes
char * toReturn = dest;
while (*src){
*dest++ = *src++;
}
return toReturn;
}
or
void copy( char ** dest, char* src){
/* overwrite pointer value with the result of malloc */
char * toCopy;
(*dest) = malloc((1+strlen(src))*sizeof(char)); //Crashes
toCopy = *dest;
while (*src){
*toCopy++ = *src++;
}
}
Related
i ma new c and i am trying sprintf along with pointers. all i get in console is return buf; as is please help me with this code.
#include <stdio.h>
char* stringa(char* str);
int main()
{
char* ss = "123";
stringa(ss);
return 0;
}
char* stringa( char* str)
{
char buf [100] ;
sprintf(buf,"hello %s", str);
return buf;
}
i tried many other ways too like sprintf_c and my computer shut down for serious. i am learning c.
Maybe this is what you want
#include <stdio.h>
char* stringa(char* dest, char* src)
int main()
{
char buf [100] ;
char* ss = "123";
printf("%s\n", stringa(buf, ss));
return 0;
}
char* stringa(char* dest, char* src)
{
sprintf(dest,"hello %s", src);
return dest;
}
In function 'char* stringa(char* str)' you are not allocating space in the heep for the char array 'buf' you are allocating space on the stack for that variable. (meaning after the function finishes, the variable 'buf' will be wiped away because it will be out of scope) therefore you must ask the compiler to allocate space in memory for this array, I recommend using malloc()
ex:
char* stringa( char* str)
{
char *buf = (char*)malloc(sizeof(char) * 100);
sprintf(buf,"hello %s", str);
return buf;
}
char* stringa( char* str)
{
char buf [100] ;
sprintf(buf,"hello %s", str);
return buf;
}
The problem with this code is that the buf char array is local to the stringa function. When the function returns, the memory occupied by the buf array is not valid anymore (for example, it could be reused later to store the content of other variables, arrays, etc.).
So when the function returns, you are giving the caller a pointer to garbage memory, to invalid data. The C compiler is trying to help you with that warning message; it's telling you: "Sorry, you are trying to pass back to the caller the address of a local variable (i.e. the buf char array) that is not valid anymore when the function terminates."
To fix this problem one option could be to allocate the char array for the output string at the call site, and let the invoked stringa function write into the caller-provided array:
#include <stdio.h>
char* stringa(char* dest, const char* str);
int main()
{
const char* ss = "123";
char buf[100];
stringa(buf, ss);
return 0;
}
/* Write the final message into 'dest'.
* Return the same dest address.
*/
char* stringa(char* dest, const char* str)
{
/* Note: better using a safe string function
* to prevent buffer overflows (e.g. sprintf_s),
* passing the maximum destination array size as well.
*/
sprintf(dest,"hello %s", str);
return dest;
}
Note that I also added some consts in your code to enforce some const-correctness for read-only input strings.
My task is like this: I should implement the strcpy function under the following constraints:
The function should use pointer expression (*(d+i))
I should implement it without using <string.h>
I'm programming in Visual Studio 2019.
I searched some source code in google and run them, but my program has a logical error. The program ends right away, each time. I don't know what I'm doing wrong.
Here's my code in Visual Studio 2019 on Windows. Please tell me what's wrong.
#include <stdio.h>
void strcpy(char*, char*);
int main()
{
char* sen1 = "Hello";
char* sen2 = "Friends";
strcpy(sen1, sen2);
printf("The result: %s\n", sen1);
return 0;
}
void strcpy(char* str1, char* str2)
{
int i = 0;
while (*(str2 + i) != '\0')
{
*(str1 + i) = *(str2 + i);
i++;
}
*(str1 + i) = '\0';
}
In addition to needing to provide writable storage for sen1, you should also check to ensure str2 != NULL in your function before dereferencing str2 (otherwise, even if you fix all other errors -- a segfault will likely result)
For example, in your code you can define a constant to use in setting the size of a sen1 array (or you can allocate storage with malloc(), calloc(), or realloc() -- save that for later). Using an array you can do, e.g.
#include <stdio.h>
#include <stdlib.h>
#define MAXC 64 /* if you need a constant, #define one (or more) */
...
int main (void)
{
char sen1[MAXC] = "Hello";
char *sen2 = "Friends";
mystrcpy (sen1, sen2);
printf ("The result: %s\n", sen1);
}
In your strcpy function, check that str2 isn't NULL before using str2 in your function, e.g.
char *mystrcpy (char *dest, const char *src)
{
char *p = dest;
if (!src || !dest) { /* ensure src or dest is not NULL */
fputs ("error: src or dest parameters NULL in mystrcpy().\n", stderr);
exit (EXIT_FAILURE);
}
do /* loop */
*p++ = *src; /* copy each char in src to dest */
while (*src++); /* (including the nul-termianting char) */
return dest; /* return pointer to dest */
}
Now you will copy your source string to your destination string in your (renamed) mystrcpy() function, receiving the results you expect:
Example Use/Output
$ ./bin/mystrcpy
The result: Friends
Look things over and let me know if you have further questions.
Two problems, at least:
String literals are not writable in C. Often the symptom is a crash (SIGSEGV).
You are not allowed to use the identifier strcpy for your own function. Use another name.
Three clean code issues, at least:
Turn int main() into int main(void) to make it properly typed.
str1 and str2 are too generic names. They don't indicate which is the source and which is the destination pointer. What about my_strcpy(char *dest, char *src)?
I'd use size_t i for the index counter instead of int, because that's the type all the string length functions and the sizeof operator return. It's also an unsigned type and can copy really long strings :-) The size_t is available after #include <stddef.h>.
You want this:
...
char* source = "Hello";
// or char source[] = "Hello";
char destination[1000]; // destination buffer long enough for playing around
my_strcpy(destination, source);
printf("%s\n", destination); // should print "Hello" if my_strcpy is corect
...
For the rest read Jens's answer.
Among the other good answers, just regarding the implementation of your strcpy function and not a detailed issue analyze of your actual code, another approach is this:
char * n_strcpy(char * dest, char const * src)
{
if (dest == NULL || src == NULL)
{
return NULL;
}
char *ptr = dest;
while ((*dest++ = *src++));
return ptr;
}
how can I change string in other function when I am using malloc?
in main:
char *myString;
changeString(myString);
changeString(char *myString){
myString = malloc((size) * sizeof(char));
myString[1] = 'a';
}
Thank you
Parameters in C are passed by value. So to modify a variable within a function, you'll have to pass the pointer to it. For example, int * to int, and char ** to char *.
void changeString(char **myString){
// free(*myString); // add when myString is allocated using malloc()
*myString = malloc(2);
(*myString)[0] = 'a';
(*myString)[1] = '\0';
}
Allocate memory in main, then pass a pointer to start of allocated memory to the function.
Also pass a variable containing the size of the allocated memory to the function, so that you can ensure that the new text does not overflow the allocated memory.
The modified string is available from main.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void changeString(char *stringptr, int sz);
int main(void)
{
const int a_sz = 16;
/* allocate memory for string & test successful allocation*/
char *myString = malloc(a_sz);
if (myString == NULL) {
printf("Out of memory!\n");
return(1);
}
/* put some initial characters into String */
strcpy(myString, "Nonsense");
/* print the original */
printf("Old text: %s\n", myString);
/* call function that will change the string */
changeString(myString, a_sz);
/* print out the modified string */
printf("New text: %s\n", myString);
/* free the memory allocated */
free(myString);
}
void changeString(char *stringptr, int sz)
{
/* text to copy into array */
char *tocopy = "Sense";
/* only copy text if it fits in allocated memory
including one byte for a null terminator */
if (strlen(tocopy) + 1 <= sz) {
strcpy(stringptr, tocopy);
}
}
I call a function global var as follow:
char *Pointer;
I then pass it into function:
char *MyChar = DoSomething (&Pointer);
which is defined as:
char *DoSomething (char *Destination)
{
free (*Destination);
//re-allocate memory
Destination = malloc (some number);
//then do something...
//finally
return Destination;
}
it only works if I use (*Destination) instead of (Destination). can someone tell me if that is correct? I still do not understand why it does not take (Destination).
It is correct, Destination is already declared as a pointer, so you pass the address of Destination in DoSomething(&Destination), that is like a pointer to pointer, then you need to dereference Destination inside DoSomething() function, for which the indirection operator * works.
But the right way, is not to pass the address of the pointer, but the pointer instead like in
DoSomething(Destination);
now, since you want to malloc Destination inside the function, you should the do this
char * DoSomething( char **Destination )
{
// free( Destination ); why?
//re-allocate memory
*Destination = malloc( some number );
//then do something...
//finally
return *Destination;
}
this is a demonstration of how you can use pointers
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *copyString(const char *const source)
{
char *result;
int length;
length = strlen(source);
result = malloc(length + 1);
if (result == NULL)
return NULL;
strcpy(result, source);
printf("The address of result is : %p\n", result);
printf("The content of result is : %s\n", result);
printf("The first character of result is # %p\n", &result[0]);
return result;
}
int main()
{
char *string = copyString("This is an example");
printf("\n");
printf("The address of string is : %p\n", string);
printf("The content of string is : %s\n", string);
printf("The first character of string is # %p\n", &string[0]);
/* we used string for the previous demonstration, now we can free it */
free(string);
return 0;
}
if you execute the previous program, you will see that the pointers both point to the same memory, and the contents of the memory are the same, so calling free in main() will realease the memory.
Here is a correct approach
char *Pointer;
//,,, maybe allocating memory and assigning its address to Pointer
//... though it is not necessary because it is a global variable and
//... will be initialized by zero. So you may apply function free to the pointer.
char *MyChar = DoSomething( Pointer );
char * DoSomething( char *Destination )
{
free( Destination );
//re-allocate memory
Destination = malloc( some number );
//then do something...
//finally
return Destination;
}
As for your code then
Type of the argument does not correspond to type of the parameter in function call
char *MyChar = DoSomething (&Pointer);
the type of the parameter is char * ( char *Destination ) while the type of argument is
char ** ( &Pointer )
As Destination is a pointer then instead of
free (*Destination);
you have to write
free( Destination );
It's because you are passing in an address of the pointer char *Pointer with the line
char *MyChar = DoSomething (&Pointer);
Since you are passing in the address of the pointer in your function DoSomething it sees the functional scope variable Destination as a pointer to an address that is the address of the pointer Pointer.
So rather than passing in the address of Pointer with
char *MyChar = DoSomething(&Pointer);
you need to pass in the pointer itself like so:
char *MyChar = DoSomething(Pointer);
which will allow you to use
free(Destination);
Notice the lack of & indicating the address of Pointer.
If I have this function foo() and I'm calling it from another function foo2(); must I free the memory in the calling function like this?
char *foo(char *str1){
char *str2;
str2 = malloc((sizeof(char) * strlen(str1)) + 1);
memcpy(str2, str1, strlen(str1) + 1)
return str2;
}
void foo2(void){
char *str1 = "Hello world!"
char *str2;
str2 = foo(str1);
...some stuff
free(str2); //Should I do this here?
}
Yes, except you don't test that your malloc is successful
You can free the allocated memory anywhere given the fact that you did the allocation, that the allocation was successful, and that the memory was not already freed.
Yeah that would work, however you have a bug:
char *foo(const char *str1)
{
char *str2 = (char *)malloc((sizeof(char) * strlen(str1)) + 1);
if (str2 != NULL)
memcpy(str2, str1, strlen(str1) + 1);
return str2;
}
void foo2
{
char *str1 = "Hello world!"
char *str2;
str2 = foo(str1);
...some stuff
free(str2);
}
Conventionally you would document the fact that the caller is responsible for freeing the returned pointer using free().
Also your foo() function is nothing more than strdup().
Yes, it is right. foo() allocates some memory and it must be freed by the caller. It's not a very good design but it works. It could be better if foo() accepts two parameters: output buffer and its size.
void foo(char* input, char* output, int* bufferSize);
If output is NULL the required size is written in bufferSize by foo().
Yes. The memory needs to be freed at some point. As you can see, you now have a tight coupling between the foo function and any of its callers. One common alternative is to pass in a pointer to a char array and the size of it. The function then returns whether it filled out the array properly. This moves the responsibility of both allocating and freeing to the caller.
bool * foo(char * str, size_t size)
{
if(size < FOO_REQUIRED_SIZE) {
return FALSE;
} else {
...
return TRUE;
}
}
void foo2(void)
{
char str[FOO_REQUIRED_SIZE];
foo(str, ARRAY_SIZE(str));
}
Instead of simply returning FALSE if the function failed, you can furthermore document the required size of the array. Or alternatively provide a function which calculates the required size and returns it.
size_t getRequiredBufSizeForFoo()
{
// Calculate how many bytes required
return ...;
}
void foo2(void)
{
size_t len = getRequiredBufSizeForFoo();
char str[len];
foo(str, len);
}