When you are doing string_copy(my_array), you are passing a char (*)[100], i.e. pointer to char[100] array to your function. But your function is expecting a char *[], i.e. array of char pointers, because you have defined your function that way.
You can fix this by making changes so that your function (string_copy()) expects a char (*)[100], instead of a char *[].
For this, you can change your function definition as:
/* Your my_array gets converted to pointer to char[100]
so, you need to change your function parameter
from `char *pointer[]` to `char (*pointer)[100]`
*/
/* static void string_copy(char *pointer []) */
static void string_copy(char (*pointer) [100])
{
strcpy(pointer[0], "Hello ");
strcpy(pointer[1], "world");
}
* Alternative Solution *
A different design/solution would be to change in your main() function so that you are actually passing a char *[], which decays into a char ** - which is fine - to string_copy(). This way you would NOT have to change your string_copy() function.
int main(int argc, const char * argv[]) {
char my_array[10][100];
int tot_char_arrs, i;
char *char_arr_ptr[10];
/* Get total number of char arrays in my_array */
tot_char_arrs = sizeof(my_array) / sizeof(my_array[0]);
// Store all char *
for (i = 0; i < tot_char_arrs; i++)
char_arr_ptr[i] = my_array[i];
/* Actually passing a char *[].
it will decay into char **, which is fine
*/
string_copy(char_arr_ptr);
printf("%s%s\n", my_array[0], my_array[1]);
}
Answer from sps on Stack OverflowWhen you are doing string_copy(my_array), you are passing a char (*)[100], i.e. pointer to char[100] array to your function. But your function is expecting a char *[], i.e. array of char pointers, because you have defined your function that way.
You can fix this by making changes so that your function (string_copy()) expects a char (*)[100], instead of a char *[].
For this, you can change your function definition as:
/* Your my_array gets converted to pointer to char[100]
so, you need to change your function parameter
from `char *pointer[]` to `char (*pointer)[100]`
*/
/* static void string_copy(char *pointer []) */
static void string_copy(char (*pointer) [100])
{
strcpy(pointer[0], "Hello ");
strcpy(pointer[1], "world");
}
* Alternative Solution *
A different design/solution would be to change in your main() function so that you are actually passing a char *[], which decays into a char ** - which is fine - to string_copy(). This way you would NOT have to change your string_copy() function.
int main(int argc, const char * argv[]) {
char my_array[10][100];
int tot_char_arrs, i;
char *char_arr_ptr[10];
/* Get total number of char arrays in my_array */
tot_char_arrs = sizeof(my_array) / sizeof(my_array[0]);
// Store all char *
for (i = 0; i < tot_char_arrs; i++)
char_arr_ptr[i] = my_array[i];
/* Actually passing a char *[].
it will decay into char **, which is fine
*/
string_copy(char_arr_ptr);
printf("%s%s\n", my_array[0], my_array[1]);
}
you need to use a pointer to the array. here is an example with 1 dimension array:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
static void string_copy(char **pointer) {
strcpy(pointer[0], "Hello ");
}
int main(int argc, const char * argv[]) {
char my_array[10];
char * p_array = my_array;
string_copy(&p_array);
printf("%s\n", my_array);
}
You can use typing for recent python version (tested on 3.9), as suggested by @Netwave in the comments:
def my_function(a: list[str]):
# You code
Which will lint as expected:

>>> isinstance(["abc", "def", "ghi", "jkl"], list)
True
>>> isinstance(50, list)
False
You could use this inside your function in order to check if your argument is a list.
pointers - Passing array of strings as parameter in python ctypes - Stack Overflow
Passing array of strings to functions C - Stack Overflow
Passing a list of strings to from python/ctypes to C function expecting char ** - Stack Overflow
How to pass array of strings as function parameter?
You think correctly. That code works. Call with, for example:
setParameters(['abc','def','ghi'])
I haven't looked at the source, but ctypes on Python 2.7 (32-bit) does pass the internal Python buffer (tested by modifying the passed string in the C function and printing it after the call in Python), which is why you should only pass Python strings as above to functions that take const char* or at least are known not to modify the string. Since Python strings are immutable writing to them under C is a no-no. Use ctypes.create_string_buffer to create a writable string to pass to non-const char*.
I needed to make the following adjustments to the for loop in the setParameters python function
for i, param in enumerate(strParamList):
if isinstance(param, bytes):
strArray[i] = c_char_p(param)
else:
strArray[i] = c_char_p(param.encode('utf-8'))
This worked if the array argument to setParameters was [b'abc', b'def'] or ['abc','def'].
You can do it like this:
void sort(char **, int);
int main()
{
char *string_database[5]={'\0'};
string_database[0]="Florida";
string_database[1]="Oregon";
string_database[2]="California";
string_database[3]="Georgia";
sort(string_database, 4);
return 0;
}
void sort(char **str, int n)
{
int i = 0;
for (i = 0; i < n; i++)
printf("The string is= %s\n",str[i]);
}
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void sort(char *strings[], int n);//Function prototype
int main()
{
char *string_database[4]={'\0'};
string_database[0]="Florida";
string_database[1]="Oregon";
string_database[2]="California";
string_database[3]="Georgia";
sort(string_database, 4);
return 0;
}
void sort(char *strings[], int n)
{
int i;
for (i=0; i<n; i++) {
printf("String %d: %s\n", i, strings[i]);
}
}
You usually pass the length of the array along with the array itself. The char *strings[] is really just sintactic sugar though, so if you want to keep the function prototype without parameter names you can use char **strings as well, so that the code could be like this:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void sort(char **, int);//Function prototype
int main()
{
char *string_database[4]={'\0'};
string_database[0]="Florida";
string_database[1]="Oregon";
string_database[2]="California";
string_database[3]="Georgia";
sort(string_database, 4);
return 0;
}
void sort(char **strings, int n)
{
int i;
for (i=0; i<n; i++) {
printf("String %d: %s\n", i, strings[i]);
}
}
Also, as Jite below points out, using a syntax such as char *strings[] might mislead you or another reader of the code into thinking they're dealing with a static matrix, while this is not true; you should therefore opt for the more straightforward char **strings syntax.
def call_c(L):
arr = (ctypes.c_char_p * len(L))()
arr[:] = L
lib.external_C(len(L), arr)
Thank you very much; that worked like charm. I also did an alternative variation like this:
def call_c( L ):
arr = (ctypes.c_char_p * (len(L) + 1))()
arr[:-1] = L
arr[ len(L) ] = None
lib.external_C( arr )
And then in C-function I iterated through the (char **) list until I found a NULL.
I have an array of strings saved as a 2d array i found it easier to parse from a .txt file. char strings[4][255]. I want to put it as a function parameter to be able to print its contents. I've tried the following but none have worked :( Segfault 11
func(char strings[][255]) func(char strings[][]) func(char ** strings) func(char * strings[])
You've already got it.
#include <stdio.h>
static void func(char *p[])
{
p[0] = "Hello";
p[1] = "World";
}
int main(int argc, char *argv[])
{
char *strings[2];
func(strings);
printf("%s %s\n", strings[0], strings[1]);
return 0;
}
In C, when you pass an array to a function, the compiler turns the array into a pointer. (The array "decays" into a pointer.) The "func" above is exactly equivalent to:
static void func(char **p)
{
p[0] = "Hello";
p[1] = "World";
}
Since a pointer to the array is passed, when you modify the array, you are modifying the original array and not a copy.
You may want to read up on how pointers and arrays work in C. Unlike most languages, in C, pointers (references) and arrays are treated similarly in many ways. An array sometimes decays into a pointer, but only under very specific circumstances. For example, this does not work:
void func(char **p);
void other_func(void)
{
char arr[5][3];
func(arr); // does not work!
}
char* parameters[513]; is an array of 513 pointers to char. It's equivalent to char *(parameters[513]).
A pointer to that thing is of type char *(*parameters)[513] (which is equivalent to char *((*parameters)[513])), so your function could look like:
void f( char *(*parameters)[513] );
Or, if you want a C++ reference:
void f( char *(¶meters)[513] );
The warning is exactly right. Your function wants an array of pointers. You're giving it an array of arrays.
Expected:
sep_foo:
+------+ +-----+
|char**|--> 0: |char*|-->"string1"
+------+ +-----+
1: |char*|-->"string2"
+-----+
*sep_foo_qty-1: |... |
+-----+
What you provided:
sep_foo:
+--------------------------------+
0: | char[MAX_STRING_LENGTH] |
+--------------------------------+
1: | char[MAX_STRING_LENGTH] |
+--------------------------------+
MAX_QTY-1: | ... |
+--------------------------------+
An array with elements of type X can "decay" into a pointer-to-X, or X*. But the value of X isn't allowed to change in that conversion. Only one decay operation is allowed. You'd need it to happen twice. In your case, X is array-of-MAX_STRING_LENGTH-chars. The function wants X to be pointer-to-char. Since those aren't the same, the compiler warns you. I'm a bit surprised it was just a warning since nothing good can come from what the compiler allowed to happen.
In your function, you could write this code:
char* y = NULL;
*sep_foo = y;
That's legal code since sep_foo is a char**, so *sep_foo is a char*, and so is y; you can assign them. But with what you tried to do, *sep_foo wouldn't really be a char*; it would be pointing to an array of char. Your code, in effect, would be attempting to do this:
char destination[MAX_STRING_LENGTH];
char* y = NULL;
destination = y;
You can't assign a pointer into an array, and so the compiler warns that the call is no good.
There are two ways to solve this:
Change the way you declare and allocate
sep_fooon the calling side so it matches what the function expects to receive:char** sep_foo = calloc(MAX_QTY, sizeof(char*)); for (int i = 0; i < MAX_QTY; ++i) sep_foo[i] = malloc(MAX_STRING_LENGTH);or, equivalently
char* sep_foo[MAX_QTY]; for (int i = 0; i < MAX_QTY; ++i) sep_foo[i] = malloc(MAX_STRING_LENGTH);Change the prototype of the function to accept what you're really giving it:
int parse(const char *foo, char sep_foo[MAX_QTY][MAX_STRING_LENGTH], int *sep_foo_qty);
Parameter 2 should be
char sep_foo[][MAX_STRING_LENGTH]
To clarify, you are passing a pointer to parse() and treating it as a pointer to a pointer. A multidimensional array in C is NOT an array of pointers. It is a single block of memory that is pointed to by the array variable. You cannot dereference it twice.
In python, function arguments are treated like separate variables, a seperate entity in relation to the original object (From my understanding. I could be wrong). Is this different in C? Are function arguments in C equal to the original thing you put in as an argument? Meaning, if you input a string into a C function as a argument, will modifying that argument from the function modify the original?