ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I think that it is a pity to manage string programming in C. So, I though to create a variadic function (like printf) but it will not print the result on screen but will malloc an string containing all the string passed in parameters.
But because it is be habitual to concatenate more than two strings, I think that someone has already develop this function. Does somebody know if the function I'm looking for already exists in a library?
Yes, that's possible, but you need to allocate a sufficient amount of memory before calling sprintf. Or you use snprintf to limit the output to n characters.
Alternatively, you could use the function asprintf which is - as far as I know - not part of the C99 standard, but a GNU extension. asprintf allocates the memory. You don't need to care about memory sizes of your final string. All you need to do after asprintf to call free when you're finished.
Thanks for your reply, I have test sprintf, and I have programmed that:
Quote:
#include <stdio.h>
#include <stdlib.h>
int
main ()
{
char * result;
char a[] = "hello";
char b[] = "world";
result = malloc (100);
sprintf (result, "%s %s", a, b);
puts (result);
return 0;
}
But there are some points that I dislike: you must allocate the memory space of the resulted string, I don't want to count how many bytes I need to malloc.
And if you concatenate a NULL pointer it prints "(null)", I would like to print nothing when a NULL pointer is found.
So, I programmed this other code, which solve my disliked points:
Quote:
#include <stdarg.h>
#include <stdio.h>
string
my_variadic_strcat (int num, ...)
{
va_list ap;
int i, size;
char * result;
char * list[num];
va_start (ap, num); // Initialize the argument list.
size = 0;
for (i=0; i<num; i++)
{
list[i] = va_arg (ap, string); // Get the next argument value.
if (list[i] != NULL)
{
size = size + strlen (list[i]);
}
}
//memory allocate required space:
result = malloc (size+1);
result[0] = '\0';
for (i=0; i<num; i++)
{
if (list[i] != NULL)
{
result = strcat (result, list[i]);
}
}
va_end (ap); //* Clean up.
return result;
}
But again, I have a problem, I don't want to count how many strings I put on the parameters... Because when you are changing your code, you can easily forgot to update the number of strings. So, I would like to enter the parameters in that way:
my_variadic_strcat2 (a, " ", b, NULL);
But because I want to accept NULL pointer (I said that if I concatenate a null pointer no action is needed), I need a null pointer different of NULL (0), so my question is reduced to this one:
Which memory address except NULL is sure to get a segmentation fault when accessed? I though with "-1" (UINT_MAX) or just "1". But I'm not sure if there is any guarantee that this values can become correct memory positions. I'm not sure because some computers take address of 32 bit and some other of 64 bit and I would like to make it independent of the architecture (I ask so much I know u_u).
You could add a stop argument, which is a string passed in as the first argument and last argument. That means that you will then loop through until you find an argument with the same stop value. Obviously, you only need to do this on the first loop; for the second loop you will know how many arguments you have and so you can just do a simple count.
[code]result1 = your_variadic_strcat("#",a," ",b,NULL,"#");
result2 = your_variadic_strcat("#stop",a,"#",b,NULL,"#stop");
[code]
As an aside you want to check that you call to malloc() worked.
Hello,
But there are some points that I dislike: you must allocate the memory space of the resulted string, I don't want to count how many bytes I need to malloc.
Please note that graemef suggests to put an string as delimiter, but now I have make that to pass a pointer, so you cannot call:
a = variadic_strcat2("#", a, " ", b, NULL, "#");
But, easily you can call:
a = variadic_strcat2(27, a, " ", b, NULL, 27);
And it will work (only one warning will be showed if -Wall flag is set when compiling).
But (allways with "but"!), it has a problem: it's limited by the size of the array "list" (10 in the example). To solve that I could use a linked-list to insert all returned strings by "va_arg", but I though it could be more eficient if I increase the size on the stack (sub esp, 4) every time "va_arg" give me an string, and then point the list to the first string returned. To do that I though I could re-declare a variable in a while an in each iteration the variable should be declared (losing the access of old declared variable with the same name):
Quote:
...
while (strcmp (iter, delimiter) != 0)
{
char * iter;
iter = va_arg(ap, char *); // Get the next argument value.
size = size + strlen(list[counter]);
counter ++;
}
...
Where iter is always a new declared variable, and not the same (put consecutively on the stack (esp register)). But it does not work like I hoped and variable is only declared the first time. Is there a way to do that?
Well... I know it seems over-elaborate, but you must understand that I would like to use this function everywhere I concatenate strings, so I need to verify there is no restriction on that function.
Yes, I have read your post, thank you, but I read it after publishing my second post, and because asprintf prints (null) when a NULL pointer is passed I said nothing.
I think asprintf is a good function to be used as itoa. And if my concatenate function is getting complex or slow I will use asprintf.
I don't understand why you are putting the arguments into an array (or linked list). You should be able to parse the parameter list twice, just call va_end() followed by a va_start() to initialise the list for a second run through.
I don't understand why you are putting the arguments into an array (or linked list). You should be able to parse the parameter list twice, just call va_end() followed by a va_start() to initialise the list for a second run through.
Oh! I didn't notice that! Really, thank you so much!
/*
PRE:
Input parameters must finish with delimiter.
All input parameters must be char *.
POST:
returned string is a concatenation of all strings between delimiter and the next occurrence of delimiter.
Null strings between delimiters will be ignored.
If all strings between delimiters are Null pointers an empty string will be returned.
*/
char *
variadic_strcat (char * delimiter, ...)
{
va_list ap;
int size, count, i;
char * result, * iter;
va_start (ap, delimiter); // Initialize the argument list.
//number of strings to concatenate
count = 0;
//result length
size = 0;
iter = va_arg (ap, char *); // Get the next argument value.
while (iter != delimiter)
{
if (iter != NULL)
{
size = size + strlen(iter);
}
count ++;
iter = va_arg (ap, char *); // Get the next argument value.
}
va_end(ap);
va_start (ap, delimiter);
result = malloc (size+1);
result[0] = '\0';
for (i=0; i<count; i++)
{
iter = va_arg (ap, char *); // Get the next argument value.
if (iter != NULL)
{
result = strcat (result, iter);
}
}
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.