char * as a reference in C - c

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.

Related

Why should I declare a String as a fixed-size array

I have this program:
#include<stdio.h>
void copy_string(char string1[], char string2[]){
int counter=0;
while(string1[counter]!='\0'){
string2[counter] = string1[counter];
counter++;
}
string2[counter] = '\0';
}
int main() {
char* myString = "Hello there!";
char* myStringCopy;
copy_string(myString, myStringCopy);
printf("%s", myStringCopy);
}
My question is, why isn't it working unless I declare myStringCopy as a fixed-size variable (char myStringCopy[12];)? Shouldn't it work if I add a \0 character after the copy as I'm doing?
It can work by doing char* myStringCopy as long as you allocate memory space for it.
for example
char* myStringCopy
myStringCopy = malloc(sizeof(char) * (strlen(myString)+1))
I might be mistaken about the +1 but I think it is like this.
char myStringCopy[12]; tells the compiler to create an array of 12 char. When myStringCopy is passed to copy_string, this array is automatically converted to a pointer to its first element, so copy_string receives a pointer to the characters.
char *myStringCopy; tells the compiler to create a pointer to char. The compiler creates this pointer, including providing memory for it, but it does not set the value of the pointer. When this pointer is passed to copy_string, copy_string does not receive a valid value.
To make char *myStringCopy; work, you must allocate memory (which you can do with malloc). For example, you could use:
char *myStringCopy;
myStringCopy = malloc(13 * sizeof *myStringCopy);
if (myStringCopy == NULL)
{
fprintf(stderr, "Error, the malloc did not work.\n");
exit(EXIT_FAILURE);
}
Also, note that 12 is not enough. The string “Hello there!” contains 12 characters, but it also includes a terminating null character. You must provide space for the null character. char myStringCopy[12]; appeared to work, but copy_string was actually writing a thirteenth character beyond the array, damaging something else in your program.
The problem is that you don't have room for mystringCopy
You need to reserve space first:
char* myString = "Hello there!";
char* myStringCopy = malloc(strlen(myString) + 1);
char* myStringCopy;
This is only pointer to char*. You must first allocate memory for myStringCopy, before start copy. When you declare it like this:
char myStringCopy[12];
compiler allocate enough memory in stack.

Copy character string to character pointer in C

Here is a simple program to demonstrate my problem.
I have a function functionB which passes pointer to a character array to functionA. functionA finds the value and stores it to a character array. The content of character array should be copied to character pointer fdate. How can I achieve this?
int functionB() {
char fdate[20];
functionA(&fdate[0]);
return 0;
}
int functionA(char *fdate) {
char date[20] = "20 May 2016";
strcpy(fdate, date);
return 0;
}
You cannot copy a string into a character pointer, but you can copy a string to a memory block pointed to by a character pointer. You cannot do this:
char *ptr;
functionA(ptr);
and expect ptr to point to the string. You need to pass a pointer to a valid memory block into your function, like this:
char buf[100];
functionA(buf);
Now the copy would work, but the function would be unsafe because it wouldn't know how much memory is available for writing its string, and could cause buffer overruns. A better approach is to pass the size of the buffer along with the buffer:
functionA(buf, sizeof(buf));
Another alternative is to pass a pointer to pointer, and have the function allocate the string dynamically. In this case, however, the caller is responsible for freeing the memory after its use:
char *ptr;
functionA(&ptr);
...
free(ptr);
...
int functionA(char **fdate) {
char date[20] = "20 May 2016";
*fdate = malloc(sizeof(date));
memcpy(*fdate, date);
return 0;
}

Changing the value of what a pointer is pointing to in C

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.

C - create a string "from" struct parameter

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.

Passing strings by value in C

I have two functions, one that creates a pointer to a string and another that manipulates it. I somehow am missing something critical, however:
int foo() {
char * mystring; // Create pointer
bar(&mystring); // Pass in address
printf("%s\n", mystring);
return 0; // There's a reason for this
}
int bar(char ** mystring) {
mystring[0] = malloc(strlen(mystring) + 1); // Since malloc will persist even after exiting bar
*mystring = "hahaha"; // Dereference
return 0;
}
Any enlightenment for my addled brain would be greatly appreciated!
C doesn't have strings as first class values; you need to use strcpy() to assign strings.
strcpy(mystring[0], "hahaha");
In addition to the other answers given, note that:
mystring[0]
is the same as
*(mystring + 0)
which is the same as
*mystring
Your malloc allocates the memory and the pointer is written to mystring but it is overwritten by the next line.
The use of malloc is necessary, but this way:
mystring[0] = malloc(strlen(mystring) + 1);
is wrong, since you can't perform strlen on mystring(because it doesn't contain any string yet and because the pointer itself is not initialized). Allocate buffer with the size of your string. for example:
int bar(char ** mystring) {
char* hello = "hahaha";
*mystring = malloc(strlen(hello) + 1);
strcpy(*mystring, hello);
return 0;
}
BTW, you could use the assignment *mystring = "hahaha"; without the malloc since this is a string stored in the data section, and the data will not be lost after returning from the function, but this way it is read-only data and you cannot modify it. The strcpy is there to copy the string to the allocated buffer.

Resources