I have a function, and I want to pass an array of char* to it, but I don't want to create a variable just for doing that, like this:
char *bar[]={"aa","bb","cc"};
foobar=foo(bar);
To get around that, I tried this:
foobar=foo({"aa","bb","cc"});
But it doesn't work. I also tried this:
foobar=foo("aa\0bb\0cc");
It compiles with a warning and if I execute the program, it freezes.
I tried playing a bit with asterisks and ampersands too but I couldn't get it to work properly.
Is it even possible? If so, how?
Yes, you can use a compound literal. Note that you will need to provide some way for the function to know the length of the array. One is to have a NULL at the end.
foo((char *[]){"aa","bb","cc",NULL});
This feature was added in C99.
You need to declare the type for your compound literal:
foobar = foo((char *[]){"aa", "bb", "cc"});
Some times variable arguments are sufficient:
#include <stdarg.h>
#include <stdio.h>
void func(int n, ...)
{
va_list args;
va_start(args, n);
while (n--)
{
const char *e = va_arg(args, const char *);
printf("%s\n", e);
}
va_end(args);
}
int main()
{
func(3, "A", "B", "C");
return 0;
}
But I generally prefer the method suggested by Matthew and Carl.
Related
This question already has answers here:
How to pass a constant array literal to a function that takes a pointer without using a variable C/C++?
(10 answers)
Closed 6 years ago.
If you had a function which took the following:
void foo(char **arr);
How can you do the following:
void foo(char* x[] = { "hello", "my", "friend" });
If this confuses you, in Java we do this by the following:
public void foo(String[] x);
foo(new String[] { "hello", "my", "friend" });
Currently, I do the following in C which I hate because it looks really ugly:
char* myArr[] =
{
"hello", "my", "friend"
};
foo(myArr);
How can you do the following:
void foo(char* x[] = { "hello", "my", "friend" });
You nearly made it ... ;-)
If doing C99 or newer use a compound literal like this:
foo((char *[]){"hello", "my", "friend"});
Mind that the called function (foo() here) has no clue how many elements the pointer array has, so you want to add a final null-pointer as sentinel:
foo((char *[]){"hello", "my", "friend", NULL});
Example:
#include <stdio.h>
#include <stdlib.h> /* for EXIT_xxx macros */
void foo(char **arr)
{
while (arr && *arr)
{
printf("%s\n", *arr);
++arr;
}
}
int main(void)
{
foo((char *[]){"hello", "my", "friend", NULL}); /* Mind the final NULL. */
return EXIT_SUCCESS;
}
This will print:
hello
my
friend
The compound literal is valid until the scope it got defined in is left (main() here). If you want to make sure it gets removed from the stack immediately after its usage put braces around the call to foo() creating a local scope/block:
int main(void)
{
{
foo((char *[]){"hello", "my", "friend", NULL}); /* Mind the final NULL. */
}
/* The compound literal passed to foo() is already deallocated here, had been
removed from the stack. */
...
Java and C are different languages with different idioms.
If it were me, I'd refrain from trying [too hard] to coerce C into "Java-like". Embrace each language on its own merits.
For your first example, the "ugly" one, you could use a CPP [C preprocessor] macro--a concept that does not exist in Java:
#define FOO(_av...) \
do { \
char *myArr[] = { _av, NULL }; \
foo(myArr); \
} while (0)
FOO("hello", "my", "friend");
But, this would probably be regarded by many as "too cute". Better to create a table of some sort.
Whenever Java does a new it is doing a heap allocation [which is slow]. That's partly because everything has to be "on the heap", more or less.
C can do this with malloc, but a good C programmer will try to avoid unnecessary heap allocations because it has globals, statics, and function scoped variables.
You must be just another victim of the people that start with java and then trying to get into c, that's why I will answer.
I want to initialize my array inside of that parameter. How can that be done?
You cannot. prior to C99
In general, this is something you could do:
#include <stdio.h>
void foo(char** arr, int size)
{
int i;
for(i = 0; i < size; ++i)
printf("%s\n", arr[i]);
}
void bar(char** arr)
{
while(*arr)
printf("%s\n", *arr++);
}
int main(void)
{
char* x[] = { "hello", "my", "friend" };
foo(x, 3);
char* null_terminated[] = { "ShadowRanger", "Correct", NULL };
bar(null_terminated);
return 0;
}
where foo() uses the size of the array explicitly, while bar() requires the array to be NULL terminated.
Can anyone suggest me what is the below line of code stands for?
static int(*pfcn[2]) (char *, ...) = { (void *)printf, (void *)NULL };
C gibberish ↔ English is a nice site that helps explain declarations
// declare pfcn as array 2 of pointer to function (pointer to char, ...) returning int
int(*pfcn[2]) (char *, ...)
{ (void *)printf, (void *)NULL }; initializes this array with the function printf() and then NULL, likely to to indicate the end.
int printf(const char *format, ...)
NULL
The static means the array is local and accessible only to the function/C file it is in.
#Lundin recommends which compiles well.
// { printf, (void *) NULL };
{ printf, NULL };
IMO, also the declaration should be
// const added
static int(*pfcn[2]) (const char *, ...) = { printf, NULL };
Note: Some C may not allow casting a NULL to a function pointer. In that case code could use
static int printf_null(const char *format, ...) {
return 0;
}
static int(*pfcn[2]) (const char *, ...) = { printf, printf_null };
... and test against printf_null rather than NULL to detect the end. Avoiding casts is a good thing.
pfcn is an array of function pointers.
The functions are those which take a variable number of args while returning an int.
It is a (hard to read) definition of an array of two functions. I would write it something like this:
#include <stdio.h>
#include <stdlib.h>
typedef int (*Function)(const char *format, ...);
static Function pfcn[2] = {printf, NULL};
The dots mean that the function will accept zero or more arguments after the first one.
I'm relatively new to the C programming language, and I'm trying to figure out how to create a function that can accept different types of data as parameters. The function is supposed to count and return the number of elements in a character or integer array. I already have two separate functions that will do this, but I would really like to be able to use one function for both tasks. Is there a way to do this in C?
Thanks in advance!
There is no standard function overloading in C (nor are there templates), but you could probably look into "printf-like" functions (or variadic functions) and maybe they can do what you need. If anything they allow for a flexible parameter list.
There is an example here of such a function that takes a variable size integer array.
Perhaps you could have a function signature such as void iterate(const char* format, ...); that you use in the following ways:
iterate("char", some_char_array); // for char arrays/strings
Or
iterate("int", some_int_array); // for integer arrays
Aniket makes a good point though, how do you count the elements in an integer array? If you pass an int array as an argument, you would need to pass the size too which defeats the purpose of counting the elements in the array (as you already know that i.e. the size).
I assume you don't know the size but you have a terminator value in the array (such as -1).
I've hacked something quick that kinda does what you need with the above assumption in mind.
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
int iterate(const char* format, ...)
{
va_list ap;
va_start(ap, format);
if (strcmp(format, "char") == 0)
{
char* array = va_arg(ap, char*);
va_end(ap);
return strlen(array);
}
else if (strcmp(format, "int") == 0)
{
int j = -1;
int* int_array = va_arg(ap, int*);
while (int_array[++j] != -1)
;
va_end(ap);
return j;
}
va_end(ap);
return 0;
}
int main()
{
printf("%d\n", iterate("char", "abcdef"));
int arr[] = {5, 4, 3, 2, 1, 0, -1};
printf("%d\n", iterate("int", arr));
return 0;
}
This prints:
$ ./a.out
6
6
So, let's assume your two functions are called sizeof_char_array and sizeof_int_array.
In C11, there is a new feature called "generic selection" that will let you do what you want with a relatively simple macro:
#define sizeof_array(X) \
_Generic (*(X), \
char: sizeof_char_array, \
default: sizeof_int_array) (X)
(I don't even have a C11 implementation to test this against, so caveat emptor!)
Prior to C11, this was sometimes accomplished with a macro using regularly named functions. You can define a macro that will call one function or the other depending on a macro argument hint:
#define sizeof_array(xtype, x) sizeof_ ## xtype ##_array(x)
int a[] = { 1, 2, 3, 4, -1 };
char b[] = "abc";
sizeof_array(int, a); /* macro expands to sizeof_int_array(a) */
sizeof_array(char, b); /* macro expands to sizeof_char_array(b) */
If the input argument is truly an array, you can use a macro to compute its size directly:
#define ARRAY_SZ(x) (sizeof(x)/((void *)x == &x ? sizeof(x[0]) : 0))
In the case of an array, the following expression is true:
(void *)arr == &arr
Because the address of an array has the same location in memory as the address of its first element.
So, the macro computes: sizeof(arr)/sizeof(arr[0]). Since the sizeof operator reports the size in bytes of its argument, the computed expression results in the number of elements in the array. However, if you are using a sentinel to compute the length, the ARRAY_SZ macro will result in a size at least one larger than the length found traversing the array for the sentinel.
In the case that the argument is not an array, then the expression results in a divide by 0 exception.
The answer is quite simple. You do need a function for this task. Just try this piece of code
#define len(array) sizeof(array)/sizeof(*array)
and that's it.
Important note: As pointed out in the comments, this will not work for dynamically allocated arrays.
You should make your function arguments take in a void * type. This way, you can pass in different types of data, and type-cast it to the one you want. However, you do need to watch out because there is no guaranteed way to correctly 'guess' the type that a void* points to.
In either case, you will need some sort of type-inferencing system to tell the C compiler which function to call. Which means, you will need to know, before-hand the type of array you might send in as a parameter to this "super function" of yours.
There is no "auto-type-inferencing" in C that can let you reflect upon the type of data at runtime. Better yet, you might have to write your own runtime environment for this to happen.
A slightly trivial hackish way to do this:
#include <stdio.h>
size_t GetLengthOfArray(size_t sizeOfOneElementInArray, size_t sizeOfTheArrayInBytes)
{
return sizeOfTheArrayInBytes/sizeOfOneElementInArray;
}
int main(int argc, char *argv[])
{
char cArr[10] = {'A','B','C','D','E','F','G','H','I','J'};
int iArr[5] = {10,20,30,40,50};
printf("%d is the length of cArr\n%d is the length of iArr",GetLengthOfArray(sizeof(cArr[0]),sizeof(cArr)),
GetLengthOfArray(sizeof(iArr[0]),sizeof(iArr)));
return 0;
}
It's not really possible, but you can make a tagged union
typedef struct {
union {
ssize_t i;
double d;
char *s;
} unknown;
char identity;
} Dynamic;
Or you can use a void pointer:
typedef struct {
void *unknown;
char identity;
} Dynamic;
/* va_arg example */
#include <stdio.h>
#include <stdarg.h>
void PrintLines ( char* first, ...)
{
char* str;
va_list vl;
str=first;
va_start(vl,first);
do {
str=va_arg(vl,char*);
if
printf ("%s\n",str);
} while (str!=NULL);
va_end(vl);
}
int main ()
{
PrintLines ("First","Second","Third","Fourth",NULL);
return 0;
}
Can we call the PrintLines function like this PrintLines("First","Second","Third",6,NULL); having integer as part of the variable argument list. If yes can anyone please explain how to do that?
so for your case you just would do it hardcoded, like:
void PrintLines ( char* first, ...)
...
str1=va_arg(vl,char*);
str2=va_arg(vl,char*);
str3=va_arg(vl,char*);
int4=va_arg(vl,int);
va_end(vl);
}
But I think that's not what you want: You sometimes may want to call PrintLines with an integer at pos 4, and sometimes with a string. Then you have to tell it what that thing at pos 4 is, because how should this poor function find out wether 112312123 is a integer or a address of a string?
So you have to supply some type-info to this function, maybe similar like it's done in printf and friends: The first arg contains a string describing the rest of the arguments. Maybe something like vsprintf will do a perfect job for you?
Consider variadic templates in C++ 11. I know it can do this, but never used it before.
When learning C I see that printf can receive many arguments as it is passed.
And I don't know how C can implement a function like this, where the user can type as many parameters as the user wants. I have thought about pointers, too but still have no bright idea. If anyone has any ideas about this type of function, please tell me.
You need to use va_args, va_list and the like.
Have a look at this tutorial.
http://www.cprogramming.com/tutorial/c/lesson17.html
That should be helpful.
You have to use the ... notation in your function declaration as the last argument.
Please see this tutorial to learn more: http://www.cprogramming.com/tutorial/c/lesson17.html
#include <stdarg.h>
#include <stdio.h>
int add_all(int num,...)
{
va_list args;
int sum = 0;
va_start(args,num);
int x = 0;
for(x = 0; x < num;x++)
sum += va_arg(args,int);
va_end(args);
return sum;
}
int main()
{
printf("Added 2 + 5 + 3: %d\n",add_all(3,2,5,3));
}
You use C varargs to write a variadic function. You'll need to include stdargs.h, which gives you macros for iterating over an argument list of unknown size: va_start, va_arg, and va_end, using a datatype: va_list.
Here's a mostly useless function that prints out it's variable length argument list:
void printArgs(const char *arg1, ...)
{
va_list args;
char *str;
if (arg1) We
va_start(args, arg1);
printf("%s ", arg1);
while ((str = va_arg(argp, char *)) != NULL)
printf("%s ", str);
va_end(args);
}
}
...
printArgs("print", "any", "number", "of", "arguments");
Here's a more interesting example that demonstrates that you can iterate over the argument list more than once.
Note that there are type safety issues using this feature; the wiki article addresses some of this.