This question already has answers here:
C function change string using pointer
(3 answers)
Closed 8 years ago.
Apparently I'm a member of a large club that just doesn't understand C-style pointers correctly. Here's my program:
void changethestring (const char * thestring)
{
thestring = "string two";
}
int _tmain(int argc, _TCHAR* argv[])
{
const char * teststring = "string one";
changethestring(teststring);
printf("The string is: %s.\n", teststring);
return 0;
}
My intent is that changethestring() should cause the pointer to point to "string two". My logic is that I'm giving the function a pointer. The function should be able to change the pointer to point to a different area in memory. And that change should persist outside the function.
Yet that's not what happens. In the printf() statement, the string is still "string one".
Can anyone explain why this is, what's happening under the covers, and how I can write a function changethestring() to change the string to which the pointer points?
You should give pointer to a pointer instead of just pointer. The reason for this is that in C, all arguments are sent by value. So in order to change the value of a variable which is a pointer, you need to send a pointer to this variable, therefore, pointer to a pointer.
UPDATE: You can define string literal outside of the changethestring function, but it's not needed, because string literals are stored in a global string table for the whole lifetime of the program. So both this:
const char* STRING_TWO_LITERAL = "string two";
void changethestring (const char ** thestring)
{
*thestring = STRING_TWO_LITERAL;
}
int _tmain(int argc, _TCHAR* argv[])
{
const char * teststring = "string one";
changethestring(&teststring);
printf("The string is: %s.\n", teststring);
return 0;
}
and this:
void changethestring (const char ** thestring)
{
*thestring = "string two";
}
int _tmain(int argc, _TCHAR* argv[])
{
const char * teststring = "string one";
changethestring(&teststring);
printf("The string is: %s.\n", teststring);
return 0;
}
should work.
By passing the pointer by value, it will get back to its initial value when you exit your function.
You should pass it by reference as Ashalynd suggest or you can also return a new value for this pointer:
const char * changethestring (const char * thestring)
{
thestring = "string two";
return thestring;
}
int main(void)
{
teststring = changethestring(teststring);
}
Related
I'm trying to write a void function that gets a pointer to a pointer of a string (char**) as a parameter, and changes the original char* so it pointed to another string, lets say "hello".
Below is the code I've written:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void change_ptr(char **str_ptr)
{
char hello[] = "hello";
char *hello_ptr = hello;
*str_ptr = hello_ptr;
}
int main()
{
char str[] = "yay";
char *str_ptr = str;
char **ptr_to_str_ptr = &str_ptr;
change_ptr(ptr_to_str_ptr);
printf("%s\n", str);
return 0;
}
As you can see, Im getting the pointer to the pointer of the char* "yay", delivering it to the function, and in the function I'm getting the pointer to "hello", and changes *str_ptr (which is the pointer to the original string) to the pointer to hello. But when I print str at the end, it prints "yay".
What am I doing wrong?
(when I debug with printing the addresses, everything seems fine.)
This works:
#include <stdio.h>
void change_ptr(const char ** str_ptr)
{
*str_ptr = "hello";
}
int main()
{
char str[] = "yay";
const char * str_ptr = str;
const char ** ptr_to_str_ptr = &str_ptr;
change_ptr(ptr_to_str_ptr);
printf("%s\n", str_ptr);
}
Note that the string "hello" in this example is read-only because it is a string literal. I added const in a few places so you are reminded of this and the compiler will warn you if you try to write to the string. The pointer str_ptr can be modified, but not the string itself.
I want to return the result of a function through the pointer *address, given as parameter. My code below prints this output:
Result:
But I was expecting:
Result: 123456
Why isn't it working as expected?
#include <stdio.h>
static void get_address(char *address) {
address = "123456";
}
int main(int argc, const char * argv[]) {
char address[34];
get_address(address);
printf("Result: %s\n",address);
return 0;
}
'address' in get_address gets a copy of the address of the start of the array address in main(). get_address changes that local pointer to the address of the local string "123456" and then does nothing with it.
What you meant to do is probably the following:
#define DEST_BUFFER_SIZE 34
static void get_address(char* address) {
const char str[] = "123456";
strcpy_s(address, DEST_BUFFER_SIZE, str);
}
int main(int argc, const char * argv[]) {
char address[DEST_BUFFER_SIZE];
get_address(address);
printf("Result: %s\n", address);
return 0;
}
Here strcpy_s is the safe version of strcpy and is used to copy the contents of the local str char-array to the memory location specified by address in get_address.
#include <stdio.h>
static void get_address(char *address) {
//Attention here
// use the reference operator
// (in your code you were affecting to the address of the variable not it's content)
*address = "123456";
}
How do I return the address of a global char* variable? I have to do this for a project. I have to write the function based on pseudo code which looks like this:
string* get_variable_address();
C doesn't have string so I assume string* will become char**. I've tried many things but I can't get it to work. What I have looks something like this:
#include <stdio.h>
char test[100] = "Get my address";
int main(void) {
char** address = return_variable_address();
printf("The address is: %s\n", *address);
return 0;
}
char** return_variable_address() {
return &test;
}
C doesn't have string so I assume string* will become char**
Probably not. A string in a C is a character array, which you can access through a char*. Therefore you can simplify your program quite a bit to get the desired result:
#include <stdio.h>
char* return_variable_address (void);
char test[100] = "Get my address";
int main(void) {
char* address = return_variable_address();
printf("The content stored at the address: %s\n", address);
return 0;
}
char* return_variable_address (void) {
return test;
}
Please note that all of this is bad practice - avoid global variables.
Keeping your following requirements in mind -
You want to return a char** where one deferencing once gives you the string "Get my address"
You want the string to be mutable.
So you can do
char test[100] = "Get my address";
char *pointer = test;
char** return_variable_address(void) {
return &pointer;
}
int main(void) {
char** address = return_variable_address();
printf("The address is: %s\n", *address);
(*address)[0] = 'F'; //Test for mutability
printf("The address is: %s\n", *address);
return 0;
}
I understand that these requirements are for some security testing and hence are so peculiar.
Demo here: Ideone
It might help you to typedef a definition of string. Then it is easy to see that the address of a string variable s is just &s as for any other address. I expect that string is used a lot through the project and the typedef will also save you from trying to change every string to char*.
To print an address use the format flag %p.
#include <stdio.h>
typedef char string[10]; // string defined as an arrary of 10 chars
string s = "Hello world"; // I've deliberately put a common error in here
string* return_variable_address( void )
{
return &s;
}
int main( void )
{
printf("Address of global var s = %p \n", return_variable_address() );
return 0;
}
I need to store the memory address of a string in an int pointer out parameter. I've created the code below to test the implementation.
void getMemAddress (int *a) {
char str[80] = "Hello world";
a = (int*)&str; // Assign memory address of str to a
printf("%s", (char*)a);
}
int main(int argc, const char * argv[]) {
int *memaddress;
getMemAddress(memaddress);
printf("%s", (char*)memaddress);
return 0;
}
printf("%s", (char*)a);
prints "Hello World" as it should but
printf("%s", (char*)memaddress);
prints null
How could I go about retrieving the actual memory address as using it to access the original string?
Thanks!
Parameters are passed by value in C. Similar issues have been answered countless times on stackoverflow.
You need this:
void getMemAddress (int **a) {
char str[80] = "Hello world";
*a = (int*)str; // Assign memory address of str to *a
printf("%s", (char*)*a);
}
int main(int argc, const char * argv[]) {
int *memaddress;
getMemAddress(&memaddress);
printf("%s", memaddress);
return 0;
}
Casting a memory address to int won't work on a 64 bit system. On a 32 bit system it works, but it's not very clean.
Other problem. You are returning the address of a local variable that is on the stack. As soon as you leave the getMemAddress function the str buffer will be overwritten by following function calls (also a classic problem). Never return the address of a local variable.
You are assining the address of &str to your function-local copy of the pointer a. What you need is to modify getMemAddress so that it takes int **a as an argument, and assign it like this:
*a = (int *) str;
then in main:
int *memaddress;
getMemAddress(&memaddress);
And one more thing-- str only exists inside your function. Once you exit the function, you won't be able to access it. To fix this, make str a char pointer and use malloc to allocate some memory for it. Then use strcpy to insert your string.
To modify something in a function, you need to pass a pointer to the thing you want to modify.
In this case you want to modify a pointer, so you need to pass a pointer to the pointer.
void getMemAddress (int **a) { // <-------------- added a *
char str[80] = "Hello world";
*a = (int*)str; // <-------------- added a *
printf("%s", (char*)*a); // <-------------- added a *
}
int main(int argc, const char * argv[]) {
int *memaddress;
getMemAddress(&memaddress); // <-------------- added a &
printf("%s", (char*)memaddress);
return 0;
}
Also, &str should be &str[0] or just str.
Also, str is a local variable, so it will cease to exist once getMemAddress returns (and then the printf call in main will probably print garbage). You could make str static, or you could return a pointer to a string literal instead (char *str = "Hello world"; *a = (int*)str;).
I've read several discussions of passing char * in C.
stackoverflow: passing-an-array-of-strings-as-parameter-to-a-function-in-c
stackoverflow: how-does-an-array-of-pointers-to-pointers-work
stackoverflow: whats-your-favorite-programmer-ignorance-pet-peeve
drexel.edu: Character arrays
Many of them include discussions of arrays, but I want to stay away from that.
I'm writing a sample program to teach myself about the passing of char * and char ** in C. This is an exercise in passing char *, without using (pointers to) arrays. Also no concerns for execution efficiency. :-)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void get_args_works(int, char **, char **);
void get_args_broken(int, char **, char *);
char *get_string(int, char **);
int main(int argc, char **argv)
{
char *string_works;
char *string_broken;
get_args_works(argc, argv, &string_works);
get_args_broken(argc, argv, string_broken);
printf("in main string_works (%p) = %s\n",string_works,string_works);
free(string_works);
printf("in main string_broken (%p) = %s\n",string_broken,string_broken);
free(string_broken);
}
void get_args_works(int argc, char **argv, char **string)
{
*string = get_string(argc, argv);
printf("in get_args_works %p string %s\n",*string,*string);
}
void get_args_broken(int argc, char **argv, char *string)
{
string = get_string(argc, argv);
printf("in get_args_broken %p string %s\n",string,string);
}
char * get_string(int argc, char **argv)
{
int i;
char *string;
string = malloc(40);
// placeholder in case -s switch not found below
strcpy(string,"-s switch not found below");
for(i = 0; i < argc; i++)
{
if(argv[i][0] == '-')
{
switch(argv[i][1])
{
case 's':
// release above malloc(40) for "-s switch not found below"
free(string);
// make room for storing variable
string = malloc(strlen(argv[++i]) + 1);
// the argv just after -s
strcpy (string,argv[i]);
break;
}
}
}
return string;
}
You can also view the same code on github
The above code is somewhat self documenting. main() declares two char * variables, and passes them as parameters to their respective get_args() functions.
Each get_args() function calls char * get_string(int, char **), using the exact same call (but different way to collect the return value).
get_string() works fine; it does a malloc() and returns the pointer back to the calling function. That code works, and each get_args() function receives the return value as I expect.
But then, when the get_args() functions return to main(), why does the dereferenced pointer value get back to main (from get_args_works(), but not the pointer's value (from get_args_broken())?
(i.e. I can see that if I dereference the pointer (&string_works) when sending as a parameter, it works. But why? Isn't char * string_broken already a pointer? Why does it need the "extra" dereference when sending as a parameter?)
I'm hoping for a winning answer that explains how you (yes, you) conceptualize sending char * as a parameter vs receiving it as the function's return value.
int get_args_broken(int argc, char **argv, char *string)
{
string = get_string(argc, argv);
printf("in get_args_broken %p string %s\n",string,string);
}
You're only modifying the string local (automatic) variable. That's not visible to the caller in any way. Note that this means you're freeing a wild pointer in main.
It's wrong for the same reason:
int get_sum(int sum, int a, int b)
{
sum = a + b;
}
is; the parameter is copied by value. Also, you're not returning an int (as you declared you would).
int get_args_works(int argc, char **argv, char **string)
{
*string = get_string(argc, argv);
printf("in get_args_works %p string %s\n",*string,*string);
}
is correct (except the missing return). You're not modifying string, which would be pointless. You're modifying the object at the location in string, which in this case is a char *.
EDIT: You would need to triple * the argv if there was a function calling main, and you wanted to set that function's variable to a different char **. E.G.
void trip_main(int *argc, char ***argv)
{
*argc = 10;
*argv = malloc(*argc * sizeof(char *));
}
void caller()
{
char **argv;
int argc;
trip_main(&argc, &argv);
}
One of the needs to use Pointer to a pointer (here get_args_works()) is to modify (or return) more than on variable from a function, as in C it's not possible to return more than one variable.
get_args_works() works 'coz, you are passing pointer to a pointer & a reference to it is there in your main().
But in get_args_broken() you are passing just a pointer. Nothing wrong here, now you do malloc() & return back the memory allocated string to get_args_broken(), still nothing wrong here. But now, this mem allocated string is local & main() does not have a reference to this var. So when you dereference char *string_broken; in main() it might cause undefined behavior.
Hope this's clear.