I have a working example of a piece of C code that I'm using to teach myself about using pointers effectively in a non-trivial application. (I have a dream to contribute a missing feature to a C library which I'm relying on.)
My sample code loo like this:
#include <stdio.h>
#include <stdlib.h>
struct config_struct {
int port;
char *hostname;
};
typedef struct config_struct config;
void setup(config*);
void change(config*);
void set_hostname(config*, char*);
void get_hostname_into(config*, char**);
void teardown(config*);
void inspect(config*);
int main() {
char* hostname;
config* c;
c = calloc( 1, sizeof(config));
setup(c);
inspect(c);
change(c);
inspect(c);
set_hostname(c, "test.com");
inspect(c);
get_hostname_into(c, &hostname);
inspect(c);
printf("retrieved hostname is %s (%p)\n", hostname, &hostname);
teardown(c);
printf("retrieved hostname is %s (%p) (after teardown)\n", hostname, &hostname);
return EXIT_SUCCESS;
}
void setup(config* c) {
c->port = 9933;
c->hostname = "localhost";
}
void change(config* c) {
c->port = 12345;
c->hostname = "example.com";
}
void set_hostname(config* c, char* new_hostname) {
c->hostname = new_hostname;
}
void get_hostname_into(config* c, char** where) {
*where = c->hostname;
}
void teardown(config* c) {
free(c);
}
void inspect(config* c) {
printf("c is at %p\n", c);
printf("c is %ld bytes\n", sizeof(*c));
printf("c:port is %d (%p)\n", c->port, &(c->port));
printf("c:hostname is %s (%p)\n", c->hostname, &(c->port));
}
It's required by the nature of the library (the function is get_session_property(session*, enum Property, void*) - thus I'm looking for a way to dereference a void pointer; I was able to successfully implement this for an int, but have been kicking my heels trying to figure out how to do it for a char* (something about a void* to int making some sense, but I can't fathom how to do it for void* to char*.
My successful implementation (with tests) for the library is on my Github fork of the project, here.
The closest I have come is:
enum Property { Port, Hostname };
void get_property(config*, enum Property, void*);
void get_property(config* c, enum Property p, void* target) {
switch(p) {
case Port:
{
int *port;
port = (int *) target;
*port = c->port;
}
break;
case Hostname:
{
char *hostname;
hostname = (char *) target;
*hostname = c->hostname;
}
break;
}
}
Which mercifully doesn't segfault, but also leaves char *get_hostname_into_here null, raising the warning (which I can't figure out:)
untitled: In function ‘get_property’:
untitled:33: warning: assignment makes integer from pointer without a cast
Full source code of my contrived example here; please when answering explain, or recommend any reading you have on using void pointers and/or good C style, it seems like everyone has a different idea, and a couple of people I know in the real world simply said "the library is doing it wrong, don't use void pointers) - whilst it would be nice if the library would make the struct public; for encapsulation and other good reasons, I think the void pointers, generic function approach is perfectly reasonable in this case.
So, what am I doing wrong in my hostname branch of the get_property() function that the char* is NULL after the call to get_property(c, Hostname, &get_hostname_into_here);
char *get_hostname_into_here;
get_property(c, Hostname, &get_hostname_into_here);
printf("genericly retrieved hostname is %s (%p)\n", get_hostname_into_here, &get_hostname_into_here);
// Expect get_hostname_into_here not to be NULL, but it is.
full source code for example (with output).
Like I said in my comments above, it's not possible to give a precise answer, because it's not clear what the aim is here. But I see two possibilities:
1: target is pointing at a char buffer
If this is the case, then it would seem that you'll need to copy the contents of your string into that buffer. This is not possible to do safely, because you don't know how big the receiving buffer is. But if you don't care about that, then you need to do something like:
strcpy((char *)target, c->hostname);
2: target is pointing at a char *
If this is the case, then the intention is presumably either to modify that char * to point at the existing string, or to dynamically create a new buffer, copy the string, and then modify the char * to point at it.
So either:
char **p = (char **)target;
*p = c->hostname;
or:
char **p = (char **)target;
*p = malloc(strlen(c->hostname)+1);
strcpy(p, c->hostname);
Note
You get the warning message because in this line:
*hostname = c->hostname;
*hostname is of type char, whereas c->hostname is of type char *. The compiler is telling you that this conversion doesn't make any sense. If I were you, I would set your compiler up to treat warnings as errors (e.g. with the -Werror flag for GCC), because warnings should always be adhered to!
The get_property function should be altered so that target is a double void pointer, meaning that you can change the pointer itself (not only the memory it refers to):
void get_property (config *c, enum Property p, void **target) {
switch (p) {
case Port:
*((int *) (*target)) = c->port;
break;
case Hostname:
*target = c->config;
break;
}
}
And then use the function like that:
int port;
int *pport = &port;
char *hostname;
get_propery(c, Port, &pport);
get_propery(c, Hostname, &hostname);
There's no answer to your question until you provide more details about the get_property function. It is clear that the void *target parameter is used to pass an external "space" in which you are supposed to place the result - the value of the requested property.
What is the nature of that recipient space?
In case of a int property it it pretty clear form your code: the pointer points to some int object in which you are supposed to place the property value. Which is what you do correctly.
But what about string properties? There are at least two possibilities here
1) The void *target parameter points to the beginning of a char [] buffer, which is supposedly large enough to receive any property value. In that case your code should looks as follows
case Hostname:
{
char *hostname = target;
strcpy(hostname, c->hostname);
}
break;
The function in this case would be called as
char hostname_buffer[1024];
get_property(c, Hostname, hostname_buffer);
This is actually the "correct" way to do it, except that you need to take certain steps to make sure you don't overrun the target buffer by some long property value.
2) The void *target parameter points to an pointer of char * type, which is supposed to receive the hostname pointer value from the property. (In that case the target actually holds a char ** value.) The code would look as
case Hostname:
{
char **hostname = target;
*target = c->hostname;
}
break;
The function in this case would be called as
char *hostname;
get_property(c, Hostname, &hostname);
This second variant doesn't look good to me, since in this case you are essentially returning a pointer to internal data of property structure. It is not a good idea to give the outside world access to the internals of [supposedly opaque] data structure.
P.S. One generally does not need to explicitly cast to and from void * pointrs in C language.
get_hostname_into_here is defined as:
char *get_hostname_into_here;
And you're passing a reference to it, namely a char**. In get_property, you're casting the void* into a char* instead of a char**, and then dereferencing it before the assignment. In order to get the string correctly, use:
case Hostname:
{
char **hostname;
hostname = (char **) target;
*hostname = c->hostname;
}
break;
Let's consider a simplified example of your get_property function which is the same in all the important ways:
void get_property_hostname(config* c, void* target) {
char * hostname = (char *) target;
*hostname = c->hostname;
}
On the first line of the function, you are making a "char *" pointer which points to the same location as "target". On the second line of the function, when you write *hostname = ..., you are writing to the char that hostname points at, so you are writing to the first byte of memory that target points to. This is not what you want; you are only giving one byte of data to the caller of the function. Also, the compiler complains because the the left-hand side of the assignment has type "char" while the right-hand side has the type "char *".
There are at least three correct ways to return a string in C:
1) Return a pointer to the original string
If you do this, the user will have access to the string and could modify it if he wanted to. You must tell him not to do that. Putting the const qualifier on it will help achieve that.
const char * get_property_hostname(config* c) {
return c->hostname;
}
2) Duplicate the string and return a pointer to the duplicate
If you do this, the caller of the function must pass the duplicate string to free() when he is done using it. See the documentation of strdup.
const char * get_property_hostname(config * c) {
return strdup(c->hostname);
}
3) Write the string to a buffer that the caller has allocated
If you do this, then it is up to the caller of the function when and how he wants to allocate and free the memory. This is what a lot of APIs in the Microsoft Windows operating system do because it offers the most flexibility to the caller of the function.
void get_property_hostname(config * c, char * buffer, int buffer_size)
{
if (strlen(c->hostname)+1 > buffer_size)
{
// Avoid buffer overflows and return the empty string.
buffer[0] = 0;
}
else
{
strcpy(buffer, c->hostname);
}
}
Then to use this function, you can do something like:
void foo(){
char buffer[512];
get_property_hostname(c, buffer, sizeof(buffer));
...
// buffer is on stack, so it gets freed automatically when foo returns
}
EDIT 1: I will leave it as an exercise for you to figure out how to integrate the ideas presented here back into your generic get_property function. If you take the time to understand what is going on here, it shouldn't be too hard, but you may have to add some extra parameters.
EDIT 2: Here's how you would adapt method 1 to use a void pointer that points to a char * instead of using a return value:
void get_property_hostname(config* c, void * target) {
*(char **)target = c->hostname;
}
Then you would call it like this:
void foobar() {
char * name;
get_property_hostname(c, &name);
...
}
Related
I am writing a program for ESP8266 on Arduino SDK. My C knowledge is not enough to create professional project so I am training my self about C programming concepts now.
I deep dive to pointers and I tried write a function that return one float value and one string value. I used pointers to do that. For float, everything went well but I cannot return string value.
Here is the my code:
float val1;
char val2;
void returnMultiple(float *fGross, char *sGross)
{
*fGross = 50.0;
char v_str[10];
dtostrf(*fGross, 5, 2, v_str);
sprintf(v_str, "%s", v_str);
sGross = v_str;
}
What is the point that I missed? My char value null or esp8266 restarting?
An option is to directly copy into the sGross.
dtostrf(*fGross, 5, 2, sGross);
Then you have to be sure the function calling has allocated enough memory.
void main()
{
float val1;
char val2[10];
returnMultiple(&val1, val2);
}
The end result will then be
void returnMultiple(float *fGross, char *sGross)
{
*fGross = 50.0;
dtostrf(*fGross, 5, 2, sGross);
}
If you define an interface you do not only need to specify the function signature but also how to call it.
Typical questions are:
What type of memory is used for buffers
Who will allocate the memory
Who will free the memory
If you define that the caller has to provide the buffer, your code could look like this:
void returnMultiple(float *fGross, char *sGross)
{
if (fGross == NULL || sGross == NULL)
return;
*fGross = 50.0;
dtostrf(*fGross, 5, 2, sGross);
}
void callerfunc(void)
{
char buf[10];
float flt;
returnMultiple(&flt, buf);
printf("flt: %f; str: %s\n", flt, buf);
}
As no dynamic memory allocation is done, nothing needs to be freed.
You might define another return type to allow for error indications.
You assign to sGross pointer the value of local variable v_str... but that data will be destroyed as soon as the function returns (it is stored in the stack, so it will be overwritten).
What you need to do is to allocate the buffer externally. You can either
Use dynamic memory with something like char *str = malloc(10 * sizeof(char)); (remembering to free it as soon as it is no more needed).
Define externally an array of chars, like in the example below
float val1;
char val2;
void returnMultiple(float *fGross, char *sGross)
{
*fGross = 50.0;
char v_str[10];
dtostrf(*fGross, 5, 2, v_str);
/* CHANGES HERE! */
sprintf(sGross, "%s", v_str);
// No need to assign to sGross the pointer of a local variable
// sGross = v_str;
}
int main( void )
{
char testString[10];
float testFloat;
returnMultiple(&testFloat, testString);
printf("%s\n", testString);
return 0;
}
In this case I would suggest to pass not only the char pointer, but also the size of the buffer.
Another solution is allocating the char array within returnMultiple() function, returning the pointer to the char array. sGross parameter in this case would become a char ** variable.
But I suggest starting with easier solutions like the one showed in my example.
First: Your problem is with the way you return the string, not the float, so I'm reducing my example to just returning the string.
There are two ways you can implement this: Either the memory for your string is allocated by the function, or by the caller. The easy way is this:
void toString(char *str, int d) {
sprinf(str, "%d", d);
}
int main(void) {
char result[12];
toString(result, 50);
puts(result, stdout);
return 0;
}
In this case, result is a 12 byte string allocated on the stack of main. 12 bytes is big enough to store the string representation of an integer, so that's safe, if you're not sure what size the result can have, then watch out.
Second option:
void toString(char **str, int d) {
char *v_str = malloc(12);
sprintf(v_str, "%d", d);
*str = v_str;
}
int main(void) {
char *result;
toString(&result, 50);
puts(result, stdout);
free(result);
return 0;
}
In this case, we pretend that the caller doesn't know how much memory is required for the result string, and let the toString function decide. It allocates as much memory as it needs for the conversion, then returns the allocated string. The caller needs to release that memory with free. Note that we've got to pass the address &result in this situation, so toString will write the pointer to the allocated string into our result variable. Double pointers like this can seem confusing to some people who are new to C, but it's conceptually similar to how you're passing a pointer to your float variable (float *fGross).
Personally, I prefer the first version when possible, because allocating memory on the stack avoids having to manage heap memory with malloc and free, a common source of memory leaks, especially for beginners. Of course, nothing prevents you from calling that version of toString with heap-allocated memory if you need to.
The point being saying w.r.t c only, as I am more comfortable in C.
I am not expecting a example which says this is how it works ... What I am expecting is why should we use the Call back function or some say it as function pointer.
I followed many blog and stack-overflow also, but not satisfied with any of those answers.
Let's say ( I am suggesting one scenario here, like sorting thing) we should use the call back thing, where a method/function will take more time for processing.
Let's say a process is there with one thread only, and the program is doing a sorting, which will take huge time ( let's assume > 1 min ). According to huge no of bloggers here we should use the function pointer. But how it would be useful ?
Any how we are having only one Program Counter and we will get some amount of time to process this process from CPU, then how it would be useful ?
If you think some other example is there to explain the function pointer concept please provide the example.
I saw some body suggesting like, if you will use function pointer, then the result u can collect later, but this sounds really awkward ! how is this even if possible ? How can u collect something from a function after returning from there ? the function would have been destroyed right !!!
In real time people use this for any change in events, so that they can get notification...( just adding a point )
I have seen some good programmer using this function pointer, I am dying to know why would I use this , surely there is something I am missing here...
Please reply, thanks in Advance.
Since there was still a bit of uncertianty in your last comment, perhaps a concrete example illustrating the points would help. Let's start with a simple example that takes a string as user input from the command line (you could prompt the user for input as well). Now let's say we want to give the user to option to tell us how they want to store the input. For purpose of this example, lets say the options are (1) to store the string normally, such that it prints on one line horizonally, (2) store the reverse of the string which will also print on one line, (3) store the string with newlines after each character so it prints vertically, and (4) store the string in reverse with embedded newlines.
In a normal approach to this problem, you would probably code a switch statement or a series of else if statements and pass the string to 4 different routines to handle the different cases. Function pointers allow you to approach the problem a little differently. Rather than 4 different input routines to handle each case, why not 1 input routine that takes a function pointer as it's argument and changes the way it handles the string based on the function passed as an argument. The input routine could be as simple as making a copy of the string (to prevent modifying argv[1], etc...) and then passing the string as an argument to a function represented by the pointer:
/* make copy of original string, pass to callback function */
char *input (char *d, char *s, char *(*cbf)(char *))
{
strcpy (d, s);
return (*cbf) (d);
}
The input function above takes as arguments the destination string d, the source string s and then a pointer to a funciton cbf (short for callback function). Let's look at the function pointer syntax quickly and digest what it tells us:
char *(*cbf)(char *)
| | \
return | argument
type | list
|
function pointer
name/label
Above, the function pointer named cbf has a return type of char *, and takes a single argument of type char *. (note: only the type is specified in the funciton pointer argument list, not both the type and argument name -- e.g. no char *str, just char *) Now that may seem like a lot to type each time you want to pass a function of that type as an argument or use it in an assignment. It is. There is an easy solution to reduce the typing required. You can use a typedef for the function pointer similar to how you use a typedef with a struct, etc. Creating a typedef of type cbf is equally easy:
typedef char *(*cbf)(char *);
The funciton pointer typedef above creates a type cbf that can be used in place of char *(*cbf)(char *) wherever the function pointer type is needed. When a typedef is used, you are relieved from specifying the return type and the argument list as well as not having to put the function pointer inside parenthesis. This reduces the original function declaration to:
char *input (char *d, char *s, cbf fname)
{
strcpy (d, s);
return fname (d);
}
Making use of a typedef for a function not only simplifies passing the functions as argument, but also simplifies creating arrays of funciton pointers as well. An array of funtion pointers can be used to simplify selecting and passing any one of a given number of functions, as needed. For our input function we create an array of function pointers each pointing to a different function that can be used to put the input string in the desired format. For example, let's say our 4 functions described above have declaration like this:
/* input processing callback functions */
char *hfwd (char *s);
char *hrev (char *s);
char *vfwd (char *s);
char *vrev (char *s);
note: each of the functions match our pointer definition of type char * and accept a single argument of type char *. Using our cbf typedef, we can easily create an array of function pointers called fnames as follows:
cbf fnames[] = { &hfwd, &hrev, &vfwd, &vrev };
The fnames array can then be used like any other array to select any one of our functions by array index. (e.g. fnames[0] is our function hfwd) This now gives us the ability to take a second input from our user, a number, to select the format for our input string. This provides the ability to use any one of our callback function by simply giving the array index for the desired function as the second argument on the command line. For example any one of the functions can be designated by calling out program with:
./progname my_string 1 /* to process the input with the hrev */
Now granted this example does not do much more than reformat a string, but from the standpoint of function pointer syntax, collecting function pointers in an array, and passing a function pointer as an argument to extend the capabilities of your code, it covers a great deal. Take a look at the following example, and let me know if you have any questions. (recall, the full function pointer syntax, in the absence of a typedef, is also included, but commented so you can compare/contrast typedef use)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXS 128
/* typedef for function pointer */
typedef char *(*cbf)(char *);
/* simple string reverse function */
char *strrevstr (char *str);
/* input processing callback functions */
char *hfwd (char *s);
char *hrev (char *s);
char *vfwd (char *s);
char *vrev (char *s);
/* input function, pointer to function will determine behavior */
// char *input (char *d, char *s, char *(*cbf)(char *));
char *input (char *d, char *s, cbf fn);
int main (int argc, char **argv) {
if (argc < 3 ) {
fprintf (stderr, "error: insufficient input, usage: %s string int\n", argv[0]);
return 1;
}
int idx = atoi(argv[2]);
if (idx > 3 || idx < 0) {
fprintf (stderr, "error: invalid input -- out of range, (0 !< %d !< 3)\n", idx);
return 1;
}
cbf fnames[] = { &hfwd, &hrev, &vfwd, &vrev };
// char *(*fnames[])(char *) = { &hfwd, &hrev, &vfwd, &vrev };
char string[MAXS] = {0};
input (string, argv[1], fnames[idx]);
printf ("\nProcessed input ('%s' '%s'):\n\n%s\n\n", argv[1], argv[2], string);
return 0;
}
/* strrevstr - reverse string, original is not preserved. */
char *strrevstr (char *str)
{
if (!str) {
printf ("%s() error: invalid string\n", __func__);
return NULL;
}
char *begin = str;
char *end = str + strlen (str) - 1;
char tmp;
while (end > begin)
{
tmp = *end;
*end-- = *begin;
*begin++ = tmp;
}
return str;
}
/* string unchanged - print horizontal */
char *hfwd (char *s)
{ return s; }
/* string reversed - print horizontal */
char *hrev (char *s)
{ return strrevstr (s); }
/* string unchanged - print vertical */
char *vfwd (char *s)
{
char *p = s;
static char buf[MAXS] = {0};
char *b = buf;
while (*p)
{
*b++ = *p++;
*b++ = '\n';
}
*b = 0;
b = buf;
while (*b)
*s++ = *b++;
*b = 0;
return buf;
}
/* string reversed - print vertical */
char *vrev (char *s)
{
char *p = strrevstr (s);
static char buf[MAXS] = {0};
char *b = buf;
while (*p)
{
*b++ = *p++;
*b++ = '\n';
}
*b = 0;
b = buf;
while (*b)
*s++ = *b++;
*b = 0;
return buf;
}
/* make copy of original string, pass to callback function */
char *input (char *d, char *s, cbf fn)
// char *input (char *d, char *s, char *(*cbf)(char *))
{
strcpy (d, s);
return fn (d);
// return (*cbf) (d);
}
Output
$ ( for i in {0..3}; do ./bin/fnc_pointer my_string $i; done )
Processed input ('my_string' '0'):
my_string
Processed input ('my_string' '1'):
gnirts_ym
Processed input ('my_string' '2'):
m
y
_
s
t
r
i
n
g
Processed input ('my_string' '3'):
g
n
i
r
t
s
_
y
m
(I am a beginner in C, maybe my question is not very smart, but I did google before I ask.)
I saw following code in git source code:
int main(int argc, char **av) {
const char **argv = (const char **) av;
// ... more code ...
}
It converts char **av to const char **argv, I thought it meant to make the argument immutable, but I wrote a program and found that both argv and argv[i] are mutable.
Question 1: What is the purpose & goodness of that line of code?
Question 2: What is the behavior of a const pointer? I did google but didn't find a good answer.
#Update
I test more according to the answers, and it seems that argv[i][j] is immutable, but argv and argv[i] is mutable.
So the const on pointer makes the original value immutable, but the pointer itself is still mutable.
Thus I guess the major purpose of the code from git is also to prevent change of the original arguments.
testing code:
#include <stdio.h>
int main(int argc, char * av[]) {
// modify value pointed by a non-const pointer - ok
av[0][0] = 'h';
printf("argv[0] = %s\n", av[0]);
// modify const pointer itself - ok
const char **argv = (const char **) av;
argv[0] = "fake";
printf("argv[0] = %s\n", argv[0]);
char *arr[] = {"how", "are", "you"};
argv = (const char **)arr;
printf("argv[0] = %s\n", argv[0]);
// modify the value itself which is pointed by a const pointer - bad, an error will be thrown,
/*
argv[0][0] = 'x';
printf("argv[0] = %s\n", argv[0]);
*/
return 0;
}
The current code could compile & run without warning or error, but if un-comment the 2 commented lines at end, then it will throw following error when compile:
error: assignment of read-only location ‘**argv’
In practice it is not very useful here (and the generated code won't change much, if the compiler is optimizing).
However, argv is not mutable, so the compiler would for instance catch as an error an assignment like
argv[1][0] = '_'; // wrong
A const thing cannot be assigned to. So a const pointer can't be assigned, and a pointer to const means that the dereferenced pointer is a location which cannot be assigned. (and you can mix both: having a const pointer to const)
BTW, main -in standard C99- is a very special function. You cannot declare it in arbitrary ways (it almost always should be declared int main(int, char**) or int main(void) ....) and you perhaps cannot call it (e.g. it cannot be recursive), but that may be different in C and in C++. So declaring int main (int, const char**) would be illegal.
1) There is really no point in using a const pointer to access the parameters later on, except to make sure they are not changed.
2) The purpose of const pointers is to make sure that they are not changed throughout the code. You can live without them, but it helps avoiding bugs.
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.
I need to create a C-function to concatenate two of any type of data and return the string that is the result of concatenation. I have done this function below, but it does not work. Could somebody help me?
// void pointer does not store value, is just the address of a memory location
char* concatenate(void* varA, int tamA, void* varB, int tamB)
{
// char is 1 byte
char* result;
char* a,b; // helpers
result = malloc((tamA+tamB)*sizeof(char));
a = varA; // "a" receives the address pointed to by the pointer varA
b = varB; // "b" receives the address pointed to by the pointer varB
*result = *result << tamA + *a;
*result = *result << tamB + *b;
result = a; // let the results point to "a"
return result; // the result is the pointer "a"
}
In C, which is what you're asking about even though your code is C++, you can't do it like that.
There's no way to figure out from a bare void * how to convert it to a string.
You must add type information of some form, such as printf()'s string using e.g. %d for decimal integers and so on.
This would be a workable prototype, I think:
char * concat_any(const char *format1, const void *data1,
const char *format2, const void *data2);
I'm not saying "optimal" or even "suitable", but it would at least be possible to implement to that prototype. The format strings could be printf()-style, or whatever.
Note that for C, this would also be very impractical, since taking a void * implies that you need a pointer to the data, always. If you wanted to e.g. concatenate two numbers, you couldn't do it like this:
char *fortytwo = concat_any("%d", 4, "%d", 2); /* BROKEN CODE */
since that passes integers instead of void *, which is very ugly. You would have to do it like this:
const int four = 4, two = 2;
const char *fortytwo = concat_any("%d", &four, "%d", &two);
which is clearly not exactly convenient.
So, it would be better to use varargs, but then you get the problem of not being able to associate different varargs with different non-variable arguments, like so:
char * concat_anyv(const char *format1, ...,
const char *format2, ...); /* BROKEN CODE */
So, how about having two formatting strings first, then trusting the caller to pass the two arguments as varargs? That would give:
char * concat_anyv2(const char *format1, const char *format2, ...);
Now we're talking. This can be trivially implemented, even: internally concatenate the two formatting strings, and call vsnprintf() two times: once to figure out buffer size, then allocate, and call it again.
Usage would be like so:
char *fortytwo = concat_anyv2("%d", "%d", 4, 2);
Done.
If I understand correctly, what you are trying to do is copy the data that varA and varB point to into a new memory buffer, one after the other, and return a char-pointer to this buffer. You can achieve this easily with the memcpy function.
char *concatenate(void *varA, int tamA, void *varB, int tamB)
{
char* result = malloc(tamA + tamB);
// copy varA to "result"
memcpy(result, varA, tamA);
// copy varB to "result" after varA
memcpy(result+tamA, varB, tamB);
return result;
}
Note that whatever data varA and varB hold it is used as is and not converted to a human readable representation.
I have two little string functions in C that I use. The first is an adaptation others have made that uses the printf model as others mentioned, you have to know what the data types are going in:
char* str(const char *fmt, ...)
{
int size;
char *buff;
va_list argp1;
va_list argp2;
va_start(argp1, fmt);
va_copy(argp2, argp1);
//calling vsnprintf with a NULL buffer simply returns what would
//be the size of the resulting string but does not include space for nul byte
size = vsnprintf(NULL, 0, fmt, argp1) + 1;
va_end(argp1);
//now actually allocate a buffer of the correct size and then fill it
buff = calloc(1,size);
assert(buff != NULL);
vsnprintf(buff, size, fmt, argp2);
va_end(argp2);
return buff;
}
With this I can concat doing a simple
char *d = str("%s%s%d", s1, s2, 25);
I just have to remember to free the string that is returned as it is allocated memory.
I have a second routine that I use for simple string concatenations that I can nest in other calls as it does internal cleanup for me:
typedef enum {FREE_NONE, FREE_ONE, FREE_TWO, FREE_BOTH} CONCAT_FREE_FLAG;
char *concat(char *one, char *two, CONCAT_FREE_FLAG f)
{
int size = strlen(one) + strlen(two) + 1;
char *buff = calloc(1,size);
assert(buff != NULL);
strcpy(buff, one);
strcat(buff, two);
if( f == FREE_ONE || f == FREE_BOTH)
free(one);
if( f == FREE_TWO || f == FREE_BOTH)
free(two);
return buff;
}
This allows me to do things like:
char *s = concat(
concat("Static ",str("%dx%d", x, y), FREE_TWO),
"Other Static", FREE_ONE);
The reason I have this is really syntactic sugar so I can pass dynamically allocated strings in, get a new dynamically allocated string but not have to worry about cleaning up the input strings.