Why isn't this function(char*) pass by ref? - c

Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void set(char* str){
str = malloc(10);
strcpy(str, "dog");
printf("\nstr = %s", str);
}
int main(){
char* s;
set(s);
printf("\n%s", s);
return 0;
}
Here's what I want to print out:
str = dog
dog
Here's what actuall gets printed out:
str = dog
(null)
Why is this? What I think I'm doing is passing an uninitalized pointer that then gets assigned a block of memory in set(), which then gets "dog" written into. What's actually going on?

There is no pass-by-reference in C. But pointers and indirection gives a facility to mimic that indirectly.
In your case, what is sent from main() to set() is the address in variable 's'. It
will have that value till malloc() statement executes. After that, str will have whatever address is returned by malloc().
When the same thing is expected in main, what should have been passed is the address
of 's' rather than what address it holds (like some of the examples above).

C is a pass-by-value language. There is no way to pass something by reference except explicitly. For your case that means expecting a pointer-to-a-pointer:
void set(char **str)
{
*str = malloc(10);
strcpy(*str, "dog");
printf("str = %s\n", *str);
}
And calling with the address of the pointer you want to 'fill in':
int main(void)
{
char *s;
set(&s);
printf("%s\n", s);
return 0;
}

Why isn't this function(char*) pass by ref?
C doesn’t have pass-by-reference. Everything is pass-by-value – it’s just that some values are also pointers to other values. Your uninitialized variable s is read when you call set(s) (which is undefined behaviour) in order to provide a value for its parameter str, then str = malloc(10) throws that value away to assign a new value to the local str.
You can pass a pointer to the pointer:
void set(char** str){
*str = malloc(10);
strcpy(*str, "dog");
printf("\nstr = %s", *str);
}
int main(){
char* s;
set(&s);
printf("\n%s", s);
return 0;
}
or return a pointer:
char* set(void) {
char* str = malloc(10);
strcpy(str, "dog");
printf("\nstr = %s", str);
return str;
}
int main(){
char* s = set();
printf("\n%s", s);
return 0;
}

You are passing an unasigned pointer to your set function, here a copy of the pointer is made and you use malloc on that copy. The original pointer in main is never updated with the new memory address.
To achieve what you want could be done this way:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void set(char** str){
*str = malloc(10);
strcpy(*str, "dog");
printf("\nstr = %s", *str);
}
int main(){
char* s;
set(&s);
printf("\n%s", s);
return 0;
}
I used a pointer to a pointer in set, and pass the memory address of the pointer s to it.

Related

function returns address of local variable [-Wreturn-local-addr] sprintf

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.

Make a function that reads (string) input

I'm new to programming and I have an assignment to make a function that reads a name. For some reason the following 'solution' does not work and the output is always something with weird chinese? characters. What went wrong?
#include <stdio.h>
#include <stdlib.h>
void input(char* a);
int main()
{
char name[8];
input(&name);
printf("%s", name);
return 0;
}
void input(char* a)
{
char buff[8];
scanf("%s", buff);
*a = buff;
}
I think the problem is in your
*a = buff;
statement because buff does not have a life outside of your function. so its memory will be lost.. so it is not safe to try and use buff in this way...
[ But as pointed out by #pablo what *a = buff; will do is copy the address of buff and put it into the memory allocated to a, which is really not what you want to do. ]
below should work and do include return from your function
#include <stdio.h>
#include <stdlib.h>
void input(char* a);
int main()
{
char name[8];
input(&name);
printf("%s", name);
return 0;
}
void input(char* a)
{
// char buff[8];
scanf("%s", a);
// *a = buff;
return;
}
one other point is to check if you are sure the name will only be 8 characters long... why not have it as 50 characters?
First off, you should pass the array to the function input() not its address. Secondly, replace scanf("%s", buff) with scanf("%s", a). This will store the string directly in the array you pass to the function.
So, the fixed code should look like:
#include <stdio.h>
#include <stdlib.h>
void input(char* a);
int main(void)
{
char name[8];
input(name);
printf("%s\n", name);
return 0;
}
void input(char* a)
{
scanf("%s", a);
}
The reason why your code doesn't work is that, you try to assign address of the local array buff to the first element of the array that you pass to the function. This shouldn't even compile or the compiler must issue a warning! If your compiler allows it to pass without any of these, that's a disaster.
Finally, the main function should be declared as int main(void) or int main(int argc, char **argv).
*a = buff; doesn't copy buff to a. Use strcpy() as
strcpy(a,buff);
complete code :
void input(char* a);
int main()
{
char name[8];
//input(&name);/** no need to pass & bcz name itself represents address */
input(name);
printf("[%s]", name);
return 0;
}
void input(char* a) {
char buff[8];
scanf("%s", buff);
//*a = buff; /* not valid **/
strcpy(a,buff);
}
This function is a problem:
void input(char* a)
{
char buff[8];
scanf("%s", buff);
*a = buff;
}
buff is local variable that is only valid while input() is running, so
returning this variable is wrong.
*a = buff; is also wrong. *a is the same as a[0], that means it is a
char. buff is an array of char, so you are assigning a pointer to an array
of char to a char variable. That doesn't sound right, it's putting apples in
the oranges box. In fact what is happening is that you are assigning the address
pointed to by buff in the memory pointed to by a.
Your compiler should have warned you about that, don't ignore the
compiler warnings, they are there to help you, not annoy you,
void input(char *a)
{
scanf("%s", a);
}
would be the correct function.
Doing
char name[8];
input(&name);
is wrong, even though the address of name and &name will be the same, but
they will have different types. name decays into a pointer, so it is a
char*. However &name is a pointer to an array of char, a different type.
The compiler should give you a warning like this:
warning: passing argument 1 of bar from incompatible pointer type
note: expected char * but argument is of type char (*)[8]
The correct call is:
input(name);
In general there is one big problem, though: You only declare 8 spaces for the
buffer. If the name is longer than 7 characters, you will have a buffer
overflow. Instead of using scanf I recommend using fgets instead, because
here you have much more control of the input and the memory boundaries.
char name[30];
fgets(name, sizeof(name), stdin);
name[strcspn(name, "\n")] = 0; // removing possible newline
scanf is not always easy to use. A name can be long and have spaces in it.
Specially for a beginner, this can be tricky. fgets is easier to use.
You don't need to pass the address of name since it's a char array. And when you do the copy in input(), you should use strcpy. The following code works:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void input(char* a);
int main()
{
char name[8];
input(name);
printf("%s", name);
return 0;
}
void input(char* a)
{
char buff[8];
scanf("%s", buff);
strcpy(a, buff);
}

change string to point to next character in function

#include <stdio.h>
void change(char *str)
{
(*str++);
return;
}
int main()
{
char *str = "ABC";
printf("before change %s \n",str);
change(str);
printf("after change %s \n",str);
return 0;
}
Output of the program is
ABC
ABC
I want output to be
ABC
BC
I don't want to return string, str needs to be modified in change function; return type of change function should remain void. I don't know how to do this.
I did try to google it but i didn't find the solution.
In C if you want to change the value of an argument to a function, you need to take that argument by pointer. And since here you are trying to change a pointer, it needs to be a pointer to a pointer:
void change(char **str)
{
(*str)++;
}
Then:
change(&str);
The expression (*str++); increments a local copy of str, not str from main. This is because C uses pass-by-value technique for function parameters.
You need to change your function to take a pointer to pointer, and pass a pointer to str in order to achieve the desired effect.
As we are in C would you need a pointer to a pointer.
I.e
void change(char **str)
{
*str = *str + 1;
}
Then
int main()
{
char *str = "ABC";
printf("before change %s \n",str);
change(&str);
printf("after change %s \n",str);
return 0;
}
See https://ideone.com/Ouo19v

C passing array of pointers

This relates to C. I am having some trouble understanding how I can assign strings to char pointers within arrays from a function.
#include <stdio.h>
#include <string.h>
void function(char* array[]);
int main(void)
{
char* array[50];
function(array);
printf("array string 0: %s\n",array[0]);
printf("array string 1: %s\n",array[1]);
}
void function(char* array[])
{
char temp[] = "hello";
array[0] = temp;
array[1] = temp;
return;
}
Ideally, I would like the main printf function to return
array string 0: hello
array string 1: hello
But I'm having trouble understanding arrays of pointers, how these pass to functions and how to manipulate them in the function. If I declare a string like char temp[] = "string" then how do I assign this to one of the main function array[i] pointers? (assuming I have my jargon right)
char temp[] = "hello"; only creates a local, temporary array inside the function. So when the function exists, the array will be destroyed.
But with array[0] = temp; you're making array[0] point to the local array temp.
After the function returns, temp doesn't exist anymore. So accessing array[0] which pointed to temp will cause undefined behavior.
You could simply make temp static, so it also exists outside the function:
static char temp[] = "hello";
Or, you could copy the "hello" string to array[0] and array[1]. For copying C-strings, you normally use strcpy.
char temp[] = "hello";
strcpy(array[0], temp);
strcpy(array[1], temp);
However, before copying you need to make sure array[0] and array[1] point to memory that has enough space to hold all characters of "hello", including the terminating null character. So you have to do something like this before calling strcpy:
array[0] = malloc(6);
array[1] = malloc(6);
(6 is the minimum numbers of characters that can hold "hello".)
how do I assign this to one of the main function array[i] pointers
Arrays cannot be assigned.
A pointer cannot hold an array, it can only refer to an array. For the latter the pointer needs to get an array's address assigned.
Referring 1.
This
char temp[] = "hello";
isn't an assigment, but an initialisation.
This
char temp[];
temp[] = "hello";
would not compile (the 2nd line errors), as an array cannot be assigned.
Referring 2.
This
char* array[50];
defines an array of 50 pointers to char, it could reference 50 char-arrays, that is 50 C-"strings". It cannot hold the C-"strings" themselfs.
Example
Applying what is mentioned above to your code whould lead to for example the following:
#include <stdio.h>
#include <string.h>
void function(char* array[]);
int main(void)
{
char* array[50];
/* Make the 1st two elements point to valid memory. */
array[0] = malloc(42); /* Real code shall test the outcome of malloc()
as it might fail and very well return NULL! */
array[1] = malloc(42);
function(array);
printf("array string 0: %s\n",array[0]);
printf("array string 1: %s\n",array[1]);
return 0;
}
void function(char* array[])
{
char temp[] = "hello";
/* Copy the content of temp into the memory that was allocated to
the array's 1st memebrs in main(). */
strcpy(array[0], temp);
strcpy(array[1], temp);
return;
}
first, you need to allocate the destination.
second, char temp[] = "hello"; in function() is local variable. you cannot use their outside of the function. use strcpy to copy the content.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(char* dest)
{
char temp[] = "hello";
strcpy(dest, temp);
return;
}
int main(void)
{
// or just char dest[10] = {0};
char *dest = malloc(10);
function(dest);
printf("dest: %s\n", dest);
}
In you program, you defined char* array[50];, so you need to create memory space for each item:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(char* a[])
{
char temp[] = "hello";
strcpy(a[0], temp);
strcpy(a[1], temp);
return;
}
int main(void)
{
char *a[50];
int i = 0;
for (i = 0; i < 50; ++i)
a[i] = malloc(10);
function(a);
printf("a[0]: %s\n", a[0]);
printf("a[1]: %s\n", a[1]);
}

How to set pointer reference through a function

In C, I am trying to set a pointer's value by sending it to a function, but the value wont change outside of the function. Here is my code:
#include <stdio.h>
void foo(char* str) {
char* new_str = malloc(100);
memset(new_str, 0, 100);
strcpy(new_str, (char*)"new test");
str = new_str;
}
int main (int argc, char *argv[]) {
char* str = malloc(100);
memset(str, 0, 100);
strcpy(str, (char*)"test");
foo(str);
printf("str = %s\n", str);
}
I want to print out:
str = new test
but this code prints out:
str = test
Any help will be appreciated. Thanks in advance.
There is no pass-by-reference in C. If you provide str as the argument to a function in C, you are always passing the current value of str, never str itself.
You could pass a pointer to str into the function:
void foo(char** pstr) {
// ...
*pstr = new_str;
}
int main() {
// ...
foo(&str);
}
As Eiko says, your example code leaks the first memory allocation. You're no longer using it, and you no longer have a pointer to it, so you can't free it. This is bad.
You need to use pointer to the pointer, untested:
#include <stdio.h>
void foo(char** str)
{
char* new_str = malloc(100);
memset(new_str, 0, 100);
strcpy(new_str, (char*)"new test");
if (str) { /* if pointer to pointer is valid then */
if (*str) /* if there is a previous string, free it */
free(*str);
*str = new_str; /* return the string */
}
}
int main (int argc, char *argv[])
{
char* str = malloc(100);
memset(str, 0, 100);
strcpy(str, (char*)"test");
foo(&str);
printf("str = %s\n", str);
}
You are just reassigning a pointer, which is a local variable in foo.
If you want to copy the string, use strcpy(str, new_str);
You could pass a reference to the pointer instead and reassign, but this can easily lead to memory leaks and is hard to maintain.
Edit: For the pseudo pass by reference see the answer by Steve.
I did it this way by returning the pointer from the function. There is no reason to use malloc in this case, so you don't have to worry about freeing.
gcc 4.4.3 c89
char* print_test(char *str)
{
char *new_str = "new_test";
printf("new_str [ %s ]\n", new_str);
str = new_str;
return str;
}
int main(void)
{
char *str = "test";
printf("str [ %s ]\n", str);
str = print_test(str);
printf("str [ %s ]\n", str);
return 0;
}

Resources