I am getting a pointer to a string passed as an argument to the function, and I need to change a few characters in the string. I'm copying the string to a char array and editing what I need to just fine, but I need to change the original string that is being pointed to into the new char[] I just created.
The function has to return void, and because the pointer being passed is just a copy of the one from main, setting it to point to the new char[] won't do anything as it will just be deleted when the function ends, so I need to actually change the string being pointed to.
*str = &newstr[0]
This is giving me the compiler error: assignment makes integer from pointer without a cast.
*str = newstr
And this is segfaulting when I run the program.
Here is the full function:
void replace(char* str, char toReplace, char replaceWith) {
int strLen = strlen(src);
char newstr[strLen];
int i;
for (i = 0; i < strLen; i++) {
if (str[i] == toReplace)
newstr[i] = replaceWith;
else
newstr[i] = str[i];
}
// How to change the value of the string being pointed to by *str to now be newstr?
}
After digesting all the comments on your question, I've come to the understanding that you're trying to invoke your function in the following manner:
char * str = "string literal"; /* compiler should have warned you about assigning
string literal to non-const pointer. */
replace( str, 'i', 'u' );
printf( "%s\n", str );
Now, the problem with that is any attempts to modify the memory that str points to will be undefined behaviour.
Your attempt at a solution was to try to change the actual pointer inside the function. But to do so, your replace function would need to accept a char**, and then allocate new memory. That's not a nice approach in this case. You really just need to modify the string in-place:
void replace(char* str, char toReplace, char replaceWith)
{
while( *str )
{
if( *str == toReplace ) *str = replaceWith;
str++;
}
}
And how to deal with the string literal? Well, the solution is simple. Make an array:
char str[] = "string literal";
replace( str, 'i', 'u' );
printf( "%s\n", str );
How to change the value of the string being pointed to by *str to now
be newstr?
You can't due to (1) the way you pass str to the function as char *s and (2) because you declare newstr as a local variable in replace. (and probably for a whole host of other reasons that are not ascertainable from the limited section of code you posted)
When you pass a pointer to a function, the function receives a copy of the pointer with it very own and very different memory address. In other words when you declare the parameter char *str in your function parameter list, that creates a new pointer. (it still points to whatever is passed in str, but its variable address is very different from the original pointer address in the calling function - so nothing you do to the address of str will ever be reflected in the calling function.) If you want to assign a new address to a pointer in a function, you must pass the original address from the caller. e.g.
void replace(char **str, char toReplace, char replaceWith)
and then in your calling routine call it with:
replace (&origPtr, char toReplace, char replaceWith)
(as a style aside: don't use CamelCase variables in C, camelcase is proper)
Finally, since the address for newstr will be destroyed when you exit function replace, your only option for assigning the address of newstr to *str is to (1) declare newstr as static, or (2) dynamically allocate newstr (e.g. char *newstr = malloc (sizeof *newstr * strLen + 1);. Then you can assign the value of newstr to str. e.g.:
void replace(char **str, char toReplace, char replaceWith) {
int strLen = strlen(*str);
int i;
char *newstr = malloc (sizeof *newstr * strLen + 1);
if (!newstr) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
for (i = 0; i < strLen; i++) {
if ((*str)[i] == toReplace)
newstr[i] = replaceWith;
else
newstr[i] = (*str)[i];
}
newstr[strLen] = 0; /* nul-terminate (or use calloc to allocate) */
free (*str); /* MUST have been dynamically allocated in caller */
*str = newstr;
}
(note: str must not have been statically declared in the calling function, and you must free the block of memory it points to or you will create a memory leak by overwriting the starting address to the block of memory it originally pointed to -- making it impossible to free the original block.)
All of these reasons are reasons why it is better to approach this problem by either changing the toReplace and replaceWith characters in place (presuming it str was an array and not a string-literal), or passing an additional array to fill with the replacement as a parameter (or as a pointer to allocate -- or return a pointer to a newly allocated block of memory containing the new string).
Let me know if you have further questions.
Related
I am struggling to write a char* passed as an argument. I want to write some string to char* from the function write_char(). With the below code, I am getting a segmentation fault.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
c = "some string";
}
int main(){
char* test_char;
write_char(test_char);
printf("%s", test_char);
return 0;
}
You have two problems (related to what you try to do, there are other problems as well):
Arguments in C are passed by value, which means that the argument variable (c in your write_char function) is a copy of the value from test_char in the main function. Modifying this copy (like assigning to it) will only change the local variables value and not the original variables value.
Assigning to a variable a second time overwrites the current value in the variable. If you do e.g.
int a;
a = 5;
a = 10;
you would (hopefully) not wonder why the value of a was changed to 10 in the second assignment. That a variable is a pointer doesn't change that semantic.
Now how to solve your problem... The first problem could be easily solved by making the function return a pointer instead. And the second problem could be solved by copying the string into the memory instead of reassigning the pointer.
So my suggestion is that you write the function something like
char *get_string(void)
{
char *ptr = malloc(strlen("some string") + 1); // Allocate memory, +1 for terminator
strcpy(ptr, "some string"); // Copy some data into the allocated memory
return ptr; // Return the pointer
}
This could then be used as
char *test_string = get_string();
printf("My string is %s\n", test_string);
free(test_string); // Remember to free the memory we have allocated
Within the function
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
c = "some string";
}
the parameter c is a local variable of the function. Changing it within the function does not influence on the original argument because it is passed by value. That is the function deals with a copy of the original argument.
You have to pass the argument by reference through pointer to it.
Also the function has a memory leak because at first the pointer was assigned with the address of the allocated memory and then reassigned with the address of the first character of the string literal "some string".
If you want to create a copy of a string literal then what you need is the following
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void write_char( char **s )
{
const char *literal = "some string";
*s = malloc( strlen( literal ) + 1 );
if ( *s ) strcpy( *s, literal );
}
int main( void )
{
char *test_char = NULL;
write_char( &test_char );
if ( test_char ) puts( test_char );
free( test_char );
}
The program output is
some string
Do not forget to allocate dynamically a character array that is large enough to store also the terminating zero of the string literal.
And you should free the allocated memory when the allocated array is not needed any more.
If you want just to initialize a pointer with the address of a string literal then there is no need to allocate dynamically memory.
You can write
#include <stdio.h>
void write_char( char **s )
{
*s = "some string";
}
int main( void )
{
char *test_char = NULL;
write_char( &test_char );
puts( test_char );
}
In C, you'll need to pass a pointer to a pointer. Your malloc call is trying to change the value of the variable that's being passed in, but it's actually only a copy. The real variable you pass in will not be changed.
Also, the way that you copy a string into a char* is not using assignment... Here's some revised code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void write_char(char** c){
size_t len = strlen("some string");
*c = (char*)malloc(len + 1); // + 1 for null termination
strncpy(*c, "some string", len);
}
int main(){
char* test_char;
write_char(&test_char);
printf("%s", test_char);
return 0;
}
String assignment in C is very different from most modern languages. If you declare a char * and assign a string in the same statement, e.g.,
char *c = "some string";
that works fine, as the compiler can decide how much memory to allocate for that string. After that, though, you mostly shouldn't change the value of the string with =, as this use is mostly for a constant string. If you want to make that especially clear, declare it with const. You'll need to use strcpy. Even then, you'll want to stay away from declaring most strings with a set string, like I have above, if you're planning on changing it. Here is an example of this:
char *c;
c = malloc(16 * sizeof(char));
strcpy(c, "Hello, world\n");
If you're passing a pointer to a function that will reallocate it, or even malloc in the first place, you'll need a pointer to a pointer, otherwise the string in main will not get changed.
void myfunc(char **c) {
char *tmp = realloc(*c, 32 * sizeof(char));
if(tmp != NULL) {
*c = tmp;
}
}
char *c = malloc(16 * sizeof(char));
strcpy(c, "Hello, world\n");
myfunc(&c);
char* test_char="string"; // initialize string at the time of declaration
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
}
int main(){
char* test_char="strin";
write_char(test_char);
printf("%s", test_char);
return 0;
}
I have a const char* string, I want to copy that string character by character to dynamic `char*.
const char *constStr = "Hello world";
char *str = (char*) malloc(strlen(constStr)+1);
while(*constStr){
*str = *constStr;
constStr++;
str++;
}
printf("%s", str);
free(str);
The problem is that previous code just copies each character of constStr to only the first index of the str. I don't know why?
As others have pointed out, you are incrementing str pointer in each iteration, so you always end up printing the end of the string.
You can instead iterate over each character without incrementing the pointer. The following code worked for me:
const char *constStr = "Hello world";
int len = strlen(constStr);
char *str = (char *) malloc(len + 1);
int i;
for (i = 0; i <= len; ++i) {
str[i] = constStr[i];
}
printf("%s", str);
free(str);
Yes you didn't null terminate the string. That was the primary problem. To be more clear, it is not that you didn't nul terminate the string which is the problem but rather your use of them where a pointer to a nul terminated char array is expected is the problem. But even if you did there was significant amount of problems in the code.
You allocated the memory and the casted the return value of malloc which is unnecessary. void* to char* conversion is implicitly done.
malloc might not be able to service the request, it might return a null pointer. It is important to
check for this to prevent later attempts to dereference the null pointer.
Then you started copying - you copied everything except the NUL terminating character. And then you passed it to printf's %s format specifier which expects a pointer to a null terminated char array. This is undefined behavior.
The one position, in the str is uninitialized - beware that accessing uninitialized value may lead to undefined behavior.
Also there is another problem, From standard ยง7.22.3.3
The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.
Yes so is is the case here? No. when you called free(str) str is not pointing to the dynamically allocated memory returned by the malloc. This is again undefined behavior.
The solution always is to keep a pointer which stores the address of the allocated chunk. The other answers already showed them (without repeating them - both of them provides a good solution).
You can use strdup or strcpy also - even if you don't need them now - get accustomed with them. It helps to know those. And yes strdup is not part of standard, it is a POSIX standard thing.
Example:
const char *constStr = "Hello world";
char *str = malloc(strlen(constStr)+1);
if( !str ){
perror("malloc");
exit(EXIT_FAILURE);
}
char *sstr = str;
while(*constStr){
*str = *constStr;
constStr++;
str++;
}
*str = 0;
printf("%s", sstr);
free(sstr);
Here's the "classical" string copy solution:
const char *constStr = "Hello world";
char *str = malloc(strlen(constStr) + 1), *p = str;
/* Do not forget to check if str!=NULL !*/
while((*p++ = *constStr++));
puts(str);
The problem is that previous code just copies each character of
constStr to only the first index of the str. I don't know why?
Use index variable.
Don't forget terminating '\0' because you have a good chance of segmentation fault.
this is a sample program demonstrating getting a string value from a func
can allocate memory inside called function itself and return
can allocate memory inside calling function and called function just updates it.
i am facing problem with the 2nd way.
is there any workaround?
/*
* main.c
*
* Created on: Sep 6, 2014
* Author: Murtaza
*/
#include<stdio.h>
#include<stdlib.h>
char* someFunc1();
void someFunc2(char* str);
void firstApproach();
void secondApproach();
int main()
{
firstApproach();
printf("\n");
secondApproach();
return 0;
}
char* someFunc1()
{
char *str = (char*)malloc(sizeof(char)*10);
str = "HELLO";
return str;
}
void someFunc2(char* str)
{
str = "Hello";
}
void secondApproach()
{
char *str = (char*)malloc(sizeof(char)*10);
someFunc2(str);
printf(str);
printf("heythere");
}
void firstApproach()
{
char *str;
str=someFunc1();
printf(str);
printf("wassup");
}
Please tell me why the second approach isn't working.
thanks!
my output is:
HELLOwassup
h>heythere
and my expected output should be
HELLOwassup
Helloheythere
void someFunc2(char* str)
{
str="Hello"; //-----the variable str is local to this function, thus it goes out of scope as
// soon as the function returns
}
void secondApproach()
{
char *str=(char*)malloc(sizeof(char)*10);
someFunc2(str);
printf(str); // -------------- here the value inside str is some garbage value.
printf("heythere");
}
CORRECTION :
void someFunc2(char **str )
{
*str = "hello";
}
void secondApproach()
{
char *str=(char*)malloc(sizeof(char)*10);
someFunc2(&str); // pass the address of the string
printf("%s", str);
printf("heythere");
}
Let's take a closer look at someFunc2:
void someFunc2(char* str)
{
/* str is a copy of the pointer that was passed in from secondApproach(). */
str = "Hello";
}
Here, you are passing a pointer by value. Thus, str in someFunc2 is a copy of the original pointer str that was passed in from secondApproach(). someFunc2 tells the copy pointer to point somewhere else, but it leaves the original str pointer alone. The solution is to pass in the address of the str pointer then tell someFunc2 to modify the pointer at that address to point to "hello".
void secondApproach()
{
char* str = (char*) malloc(sizeof(char) * 10);
someFunc2(&str); // Pass in the address of str.
printf("%s", str);
printf("heythere");
}
void someFunc2(char** str)
{
*str = "hello";
}
When you write a string between quotes and use it directly as:
a char* -> it gets created in a mutable place in memory, and gives its address to the pointer variable its assigned to. It is still in memory as long as that variable referencing it is not NULL.
an argument -> it gets created as char* and passed to the function (and treated there as a char*), then automatically disposed from memory (i.e. you can't access it or reference it anymore) ..
So, the only situation when a string is actually mutable is when you assign it to a char[], then it gets created in readonly memory and copied into to the stack .. ( the copy on the stack is what the char[] variable will point to )
If you think about it for some time, you realize that this is one of the benefits of dynamic memory: you can create a char* that is mutable, and since it is just a pointer, you don't need to specify the size of the string it is going to point at. So you can see how useful this would be ..
Also, it's worth to note that in functions:
if you pass a string, the variable in the function itself is treated as a char pointer and most likely would try to modify it, and if it's readonly that would raise a Segmentation Fault. So functions are assuming you know what you're doing ..
if you want a function to be able to modify a string directly (i.e string = "somestring") then pass it a pointer to the actual string, else the modification will only be local to the function. That's because the string is a "pointer to char", so the function can't modify the string as a whole. But that also means that a function can modify the string's characters individually ( obviously, because it has a pointer for characters: the string ). If you pass it, however, a string pointer (char**), the function can modify the string directly (*string = "whatever") and can also modify the characters individually (*string[1] = 'C'). Which choice you need depends entirely on the purpose of the function ..
Now, for your specific example, you can do one of two ..
Using a pointer to a pointer to a char (string pointer)
void someFunc2(char** str)
{
*str = "Hello";
}
Using a pointer to char (string)
void someFunc2(char* str)
{
char *k = "Hello";
for(int i = 0; i < 5; ++i)
str[i] = k[i];
}
This is one of the most controversial and advanced topics in C. No matter what type of C programming you're doing, you have to understand these core concepts ..
Have a
typedef struct person {
char name[20]
char surname[20]
} person_t;
I need to create a string like XXXXXX:YYYYYY with the function like
char* personToString(person_t *p). I tried to make it:
char* personToString(person_t* p) {
int n1,n2;
n1=strlen(p->name);
n2=strlen(p->surname);
char *p = (char*) malloc((n1+n2+2)*sizeof(char));
strcat(p,puser->name);
strcat(p,":");
strcat(p,puser->surname);
return p;
}
This give me a reasonable output but I have some errors testing with valgrind! I also think that there is a way more classy to write the function!
When you malloc memory for p the memory will hold garbage values. Strcat will append a string after the null character, but in an uninitialized string will hold random values.
Replace the first strcat with strcpy.
You need to
strcpy(p,puser->name);
not
strcat(p,puser->name);
malloc does not initialize the buffer to zero, so strcat is searching for a null byte in p first and probably not finding one, reading past the end of the buffer and thus crashing.
Instead of one strcpy plus two strcat you can also write one call to sprintf:
sprintf(p, "%s:%s", puser->name, puser->surname);
First you should call string copy, then strcat:
strcat(p,puser->name);
should be:
strcpy(p,puser->name);
because memory allocated with malloc function keeps values garbage, by doing strcat for first you are concatenating after garbage -- it also brings Undefined behaviour in your code.
You can use void* calloc (size_t num, size_t size); instead of malloc(), calloc function initialized allocated memory with 0 (then strcat() no problem).
Also dynamically allocated memory you should deallocate memory block using void free (void* ptr);) explicitly.
This looks good to me,
char* personToString( struct person_t *p )
{
int len = strlen(p->name) + strlen(p->surname) + 2; // holds ':' + NULL
char *str = malloc( len ); // Never cast malloc's return value in C
// Check str for NULL
if( str == NULL )
{
// we are out of memory
// handle errors
return NULL;
}
snprintf( str, len, "%s:%s", p->name, p->surname);
return str;
}
NOTE:
Never cast malloc's return value in C.
Use snprintf when multiple strcat is needed, its elegant.
free the return value str here in caller.
Fixed struct and char variables.
How to pass the param like char * as a reference?
My function uses malloc()
void set(char *buf)
{
buf = malloc(4*sizeof(char));
buf = "test";
}
char *str;
set(str);
puts(str);
You pass the address of the pointer:
void set(char **buf)
{
*buf = malloc(5*sizeof(char));
// 1. don't assign the other string, copy it to the pointer, to avoid memory leaks, using string literal etc.
// 2. you need to allocate a byte for the null terminator as well
strcpy(*buf, "test");
}
char *str;
set(&str);
puts(str);
You have to pass it as a pointer to the pointer:
void set(char **buf)
{
*buf = malloc(5 * sizeof(char));
strcpy(*buf, "test");
}
Call it like this:
char *str;
set(&str);
puts(str);
free(str);
Note that I have changed the malloc call to allocate five characters, that's because you only allocate for the actual characters, but a string also contains a special terminator character and you need space for that as well.
I also use strcpy to copy the string to the allocated memory. That is because you are overwriting the pointer otherwise, meaning you loose the pointer you allocate and will have a memory leak.
You should also remember to free the pointer when you are done with it, or the memory will stay allocated until the program ends.
C does not support pass by reference. But you can pass a pointer to your pointer, and set that:
void set(char **buf)
{
*buf = malloc(5*sizeof(char)); //5, to make room for the 0 terminator
strcpy(*buf,"test"); //copy the string into the allocated buffer.
}
char *str;
set(&str);
puts(str);
You to pass a pointer to a pointer, char**: there are no references in C.
void set(char** buf)
{
*buf = malloc(5); /* 5, not 4: one for null terminator. */
strcpy(buf, "test");
}
Note that:
buf = "test";
does not copy "test" into buf, but points buf to the address of the string literal "test". To copy use strcpy().
Remember to free() returned buffer when no longer required:
char* str;
set(&str);
puts(str);
free(str);
C is pass-by-value. There is no pass-by-reference.
In the example given above by hmjd, it should be:
strcpy(*buf, "test");
C cannot not pass function arguments by reference, C always passes them by value.
From Kernighan & Ritchie:
(K&R 2nd, 1.8 Call by value) "In C all function arguments are passed by "value""
To modify a pointer to T, you can have a pointer to pointer to T as the function argument type.