Related
I have been trying and searching online for too long without any success. I've tried a lot of the suggested answers but nothing has worked for me.
I want to basically send in a char*. It can make it NULL if necessary, but would rather the function modify a char* that already has something.
Example:
char *old = "kit";
function(old){ //does stuff and writes "kat" to old}
printf("new = %s", old);
And
result: new = kat
How can I do this?
Thanks
EDIT:
What I'm currently trying:
calling_function(char *in){
char **old = NULL;
function(&old);
printf("old in calling function is now = %s", *old);
}
function(**old){
<does stuff to get char *another_string = "kat">
*old = another_string;
printf("old is now = %s ", *old);
}
And the result is:
old is now "kat"
old in calling function is now =
and it immediately exist the system with an unspecified error exit(-1) then hangs.
A char* is nothing more an address that points to some bytes which are then interpreted as a string, how to do what you need really depends on what you need to do.
If you want to change a character of the string then a normal char* (non const) pointer will be enough:
void function(char *data) {
data[0] = 'a';
}
If, instead, you want to replace the whole string with another one (possibly of different length), then you will need to pass the address that contains the address, so that you can directly replace it to a new address (that points to a different string):
void function(char **data) {
*data = strdup("newstring");
// strdup is used because a string literal must be considered as const
// otherwise you could invoke UB by modifying the returned string
}
char *value;
function(&value);
An example for passing integer as reference is here: Passing by reference in C
For your example, the value can be changed in the function as below:
char *old = "kit";
/* this will print kit */
printf("old = %s",old);
function(old);
/* this will print kat */
printf("updated old = %s", old);
function(char *old) {
*old = "kat"
}
The line
char *old = "kit";
Can cause trouble because old may point to read-only memory. What you want to do is this:
char old[128]; // or however many you need
function(old){ //does stuff and writes "kat" to old // You can use sprintf for this}
printf("new = %s", old);
Which will allocate old on the stack, where it can be modified.
This will take an existing char * and change it.
char* old = "kit";
void changingFunction( char* pointer ) {
strcpy( pointer, "kat" );
/* or just pointer[1] = 'a'; */
}
changingFunction(old);
printf("new = %s\n", old);
Be careful, though. Remember that you're essentially dealing with an array, and the function doesn't know the size of the array. You always want to stay within the bounds of the array.
Consequently, you should make the function more advanced:
void changingFunction( char* pointer ) {
char * newString = "kat";
strncpy(pointer, newString, strlen(pointer));
}
By using strncpy, you ensure that you stay within your bounds, and since you're dealing with a null terminated char*, you can use strlen to find how big your bounds are.
You can change your function prototype to
void myFunction(char** pold)
and within that function, you are free to write
*pold = "kat";
And call the function like this: myFunction(&old);
But beware; this approach has dangers:
1) You may leak memory as the previous string (i.e. what was old originally pointing to?) may be dangling.
2) *pold = "kat"; assigns read-only memory to *pold. This is because "kat" is probably added to a string literal pool on program startup by the C runtime library. Attempting to modify the string (e.g. (*pold)[0] = 'K') is undefined behaviour. Using *pold = strdup("kat"); circumvents this problem.
I learned something by trying to answer this question! Here's my program that does the operation:
#include <stdio.h>
void f(char* str)
{
strcpy(str, "kat");
}
int main(void) {
// char* str = "kit"; // Initializing like this causes a crash!
char str[4]; // This initialization works
strcpy(str, "kit");
f(str);
printf(str); // Prints "kat"
return 0;
}
There are obvious issues with safety, but what was strange to me is that if you declare str using the commented-out line, the program crashes. I didn't realize that initializing a string literal like that gave you a pointer to read-only memory. That's very non-obvious to me, so I was confused when my little program crashed.
I think it's important to point out that fact first and foremost because it's central to why a naive solution to the problem wouldn't necessarily work. Interesting.
Currently in the process of learning a bit of c, but I'm having issues with strings.
I simply want to return a string using a function. This is to be part of a bigger program that's supposed to get the word from an external file, but I want a simple function like this just to get going.
PS. Yes the bigger program is for school. I don't want to simply copy code, i want to understand it. Just throwing that out there.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* teststring()
{
return (char*)"donald duck";
}
int main()
{
char word[20];
word = teststring();
return 0;
}
I've tried various variations of returning a string, but my problem is that I'm unsure what to use as return type for the function and how to return it.
This is the most common error i get.
[Error] incompatible types when assigning to type 'char[20]' from type 'char *'
I've tried with different return types, declaring and initializing a char array and return it, and my latest test type conversion.
Thanks in advance.
Arrays (more properly, expressions of array type) cannot be the target of an assignment; you cannot copy the contents of one array to another using the = operator.
For strings, you will need to use either the strcpy or strncpy functions:
strcpy( word, teststring() ); // assumes word is large enough to hold the
// returned string.
For other arrays, use memcpy.
You'd better add const modifier to the function teststring() as it returns a pointer to a const string. You cannot reassign word which is the address of char[20] to a pointer that points to a constant string. It must be copied.
#include<string.h>
#include<stdio.h>
const char* teststring()
{
return "donald duck";
}
int main()
{
char word[20];
strcpy(word, teststring());
printf("%s", word);
return 0;
}
I am trying to write 3 function:
the first one: "read_comp" initialize a char pointer and assign it what function "readAndRemove" return.
readAndRemove read line from the user and remove any spaces before the string and return a pointer to the string without the spaces in the start.
then the "read_comp" print the string got by "readAndRemove" - the one without the spaces.
the last function - the one that i have problem with...
function "findComplex":
what i am trying this function to do is just to get char pointer and print the string that function got.
void read_comp(void)
{
char *str = readAndRemove();
printf("%s\n",str);
findComplex(&str);
}
-------------
char * readAndRemove() /**function to read rest of input and remove first space**/
{
char tempChar[30];
fgets(tempChar,30,stdin);
char* ptr = strtok(tempChar, " ");
return ptr;
}
--------------
void findComplex(char* str)
{
printf("in findComplex:%s\n",str);
}
(sorry if the start was irrelevant but i thought maybe there is problem with the way i am doing everything...)
so i tried to fix and change few things:
change this: define char *str; as global parameter
and chanege the function:
void read_comp(void)
{
*str = readAndRemove();
printf("%s\n",str);
findComplex(str);
}
char * readAndRemove() /**function to read rest of input and remove first space**/
{
char tempChar[30];
fgets(tempChar,30,stdin);
char* ptr = strtok(tempChar, " ");
return ptr;
}
void findComplex(char* str)
{
printf("%s\n",str);
printf("in findComplex:%s\n",str);
}
The variable str in the read_comp function is already a pointer. Your use of the address-of operator & makes that a pointer to a pointer (i.e. type char **). Just make sure the findComplex function is prototyped before you call it, and don't use the address-of operator.
You have a larger problem though, and that is that the readAndRemove function returns a pointer to a local variable. Remember that local variables are stored on the stack, and that when a function returns that stack space is reclaimed to be reused by other function calls. Create the array in the read_comp function instead, and pass it together with its size to the readAndRemove function.
If you enable warnings in your compiler (and I'm saying if as in "please do this!") you would get a warning saying "returning pointer to local variable" or something like that for this:
char * readAndRemove() /**function to read rest of input and remove first space**/
{
char tempChar[30];
fgets(tempChar,30,stdin);
char* ptr = strtok(tempChar, " ");
return ptr;
}
You MUST not return pointers to local variables, because the space used by tempchar (which ptr will point into) is going to be reused by the next function when you return from this function - and most likely the next function will write something OTHER than your string into this memory.
The solution, I would suggest, is to move tempchar up to read_comp() [1], and pass the string to readAndRemove.
[1] Please try to decide whether you use "camelcase" or "_" names. Either your functions should be read_and_remove and read_comp or readAndRemove and readComp. I almost wrote it wrong because I expected to find the same style in both functions - this sort of thing can drive you mad when you later try to change something.
In short, I would like to do this:
const char **stringPtr = &getString();
However, I understand that you can't & on rvalues. So I'm stuck with this:
const char *string = getString();
const char **stringPtr = &string;
I can live with two lines. Am I introducing problems with this hack? I should have no fear of passing stringPtr out of the function it is declared in, right?
Edit: My apologies for not originally including the full context.
I have taken on the summer project of building a video game from the ground up in C using OpenGL for graphics. I'm reading configuration data from a text file using libconfig.
One of the convenience functions for finding a specific string from your configuration file looks like this:
int config_setting_lookup_string(const config_setting_t *setting,
const char *name, const char **value)
{
config_setting_t *member = config_setting_get_member(setting, name);
if(! member)
return(CONFIG_FALSE);
if(config_setting_type(member) != CONFIG_TYPE_STRING)
return(CONFIG_FALSE);
*value = config_setting_get_string(member);
return(CONFIG_TRUE);
}
The way that value is assigned means that if you give the function an uninitialized value, it attempts to derefence undefined garbage, which pretty much always causes me a segfault. My current workaround for this issue is to initialize value to another pointer first, like so:
const char *dummyPtr;
const char **fileName = &dummyPtr;
config_setting_lookup_string(foo, "bar", fileName);
So I am trying to figure out the best way to rewrite the last part of the function so that I won't have to perform this two-step initialization. I was thinking that the changed function would look like this:
int config_setting_lookup_string(const config_setting_t *setting,
const char *name, const char **value)
{
config_setting_t *member = config_setting_get_member(setting, name);
if(! member)
return(CONFIG_FALSE);
if(config_setting_type(member) != CONFIG_TYPE_STRING)
return(CONFIG_FALSE);
const char *string = config_setting_get_string(member);
value = &string;
return(CONFIG_TRUE);
}
If you're calling a function that needs a const char**, you could do it like this:
const char *s = getString();
myFunction(&s);
Since s is allocated on the stack in the above example, if you want to return a const char** from your function, you will need to put it on the heap instead:
const char **sp = malloc(sizeof(const char *));
*sp = getString();
return sp;
HTH
string in your case is a local, so taking the address of it is a bad idea since the memory for the local can (and likely will be) re-used for other purposes when you leave the method. In general, it is not a good idea to use the address of a local variable outside of its scope.
What are you trying to achieve?
No, you can't change config_setting_lookup_string() in the way you've described. You're returning a pointer to the string variable, but as soon as that function ends that variable goes out of scope and is destroyed.
You can, however, fix your initial problem quite easily. Leave the definition of config_setting_lookup_string() as it is, and call it like so:
const char *fileName = NULL;
config_setting_lookup_string(foo, "bar", &fileName);
From the added information, it seems what you are trying to do is call a function which wants to return a string through one of the function arguments. The best way to do this in my opinion would be something like:
const char* fileName;
config_setting_lookup_string(..., &fileName);
(...)
return fileName;
This will allocate room for a const char* on the stack. The function call will fill the pointer with the address of the string it wants to return. This pointer value can then be passed out of the function if needed (unlike the pointer to the pointer, which would point to the stack, and be invalid when the function returns).
Note that initializing fileName with "getString()" would presumably leak memory, since the pointer to the returned string would be overwritten, and the string never deallocated.
You need the two lines. However, string is a local variable on the stack, once it goes out of scope, you may not have a pointer to the data returned by getString().
I like nornagon and caf's solution,
const char *fileName;
config_setting_lookup_string(foo, "bar", &fileName);
but if you can change config_setting_lookup_string you could also do it this way:
int config_setting_lookup_string(..., const char *&value)
{
...
const char *string = config_setting_get_string(member);
value = string;
...
}
const char *fileName;
config_setting_lookup_string(foo, "bar", fileName);
If you return stringPtr, you will be returning a pointer to a local variable (string). So no, you can't do that.
Why are you trying to do this? That might allow us to make better suggestions.
Update:
Okay, now I see what you're trying to do. You're doing it wrong:
value = &string;
If value is meant as an output parameter, the above line cannot work because you're assigning to a local variable.
Don't let the extra level of indirection confuse you. If you were writing a function that had an output parameter of type T, you'd write it as:
void foo(T* value)
{
*value = GetT();
}
Now replace T with const char*:
...
*value = string;
...
And now you're not involving any temporary, local variables. Of course, that's how the code was originally written (and that part of it was correct), so that doesn't really help you. To address your intent, you should:
Make config_setting_lookup_string do assert(value != NULL).
Audit the callers of the function and fix them to stop passing garbage. They should be doing:
const char* foo;
config_setting_lookup_string(..., &foo);
and NOT:
const char** foo;
config_setting_lookup_string(..., foo);
I was wondering if you could help me out with a C string problem I don't quite understand. I have a function to which I send 3 char pointers. Within this function, the char pointers are shifted and modified correctly. However, when I return to the main function from which they are called, said functions are not changed. Am I passing by value be mistake? Here is an example of my code:
int main(void)
{
LPSTR path = (char*)malloc(strlen(START_PATH));
strcpy( path, START_PATH );
char* newstr = (char*)malloc(PATH_SIZE);
TrimVal(path, "*.*", newstr);
//Do Stuff
return 0;
}
void TrimVal(char* modify, char* string, char* newstr)
{
newstr[0] = '\0';
modify = strncat(newstr, modify, (strlen(modify) - strlen(string)));
return;
}
NOTE: Assume PATH_SIZE is a size value, and START_PATH is a char array
In doing this
modify = strncat(newstr, modify, (strlen(modify) - strlen(string)));
You are modifying the pointer, not what the pointer points to.
When you pass in path to TrimVal. It will pass in the memory location of path e.g. 0x12345
When you do the modify = you are saying, change the local variable modify to be a new memory location, e.g. 0x54321
When you return to main, it only has a pointer to 0x12345, and when it looks there, nothing has changed.
You can easily fix your problem by doing
{
...
TrimVal(&path, "*.*", newstr);
...
}
void TrimVal(char** modify, char* string, char* newstr)
{
newstr[0] = '\0';
*modify = strncat(newstr, *modify, (strlen(*modify) - strlen(string)));
return;
}
void TrimVal(char* modify, char* string, char* newstr)
Changing the values of modify, string, or newstr inside the TrimVal() function has no effect on the variables at the calling function.
Changing the contents of modify, string, or newstr inside the TrimVal() function will be reflected on the variables at the calling function.
So
void TrimVal(char* modify, char* string, char* newstr)
{
newstr[0] = '\0'; /* will be reflected in the calling function */
modify = "a new string"; /* won't be reflected */
}
I think your function, with a little clearing of code, could do what you want.
Oh ... and you have a memory leak with the path variable: you malloc some space for it and immediately afterwards lose the address of that space by assigning a different value to the path variable.
A couple of points in addition to the many other good ones raised in this thread:
LPSTR path = (char*)malloc(strlen(START_PATH));
If this is C, you should not cast the return value of malloc. (See C FAQ 7.7b.
More importantly, strlen does not include the terminating \0 in its calculation. So, the memory path points to is one character short of the required amount of memory to hold START_PATH plus the \0. Therefore:
strcpy(path, START_PATH);
invokes undefined behavior by writing one past the memory pointed to by path.
If you expect your char* variable to be modified in the function and you want to pass by reference, you need to pass it as char* . Remember, you are passing the pointer by reference, so there needs to be an extra layer of indirection (passing char does pass something by reference - a single character!)
I see a problem with the first two statements. You are declaring path as a pointer char and allocating memory for it that is stored in this address holder. In your next statement, you are changing the value in path, pointing it to the start of your char array, START_PATH. The memory you allocated is now lost.
Also, strncat does not call malloc to concatenate. It is expected that you are passing in a buffer large enough to hold the concat, and this is a potential security risk (buffer overrun).
Just one comment about your style of casting the return type of the malloc call. When casting this can hide errors.
This would be a much better style.
Include the stdlib.h and try and make the call to malloc as type independent.
char *ptr_char = NULL;
ptr_char = malloc(sizeof(*ptr_char));
Hope this helps,
C doesn't really have a pass-by-reference. What you are doing here is passing pointers by value. A string in C is represented by a pointer to char. So in the function TrimVal you can modify the contents of the string (that is, the pointed-to data), but not the pointer itself.
strncat modifies the contents of the first parameter and returns the same value.
If you want to change the value of path within TrimVal, you should pass a pointer to a pointer, like so:
...
TrimVal(path, "*.*", newstr);
...
void TrimVal(char** modify, char* string, char* newstr)
{
newstr[0] = '\0';
*modify = strncat(newstr, *modify, (strlen(*modify) - strlen(string)));
return;
}