I am trying to pass an array of character strings (C style strings) to a function. However, I don't want to place a maximum size on length of each string coming into the function, nor do I want to allocate the arrays dynamically. Here is the code I wrote first:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void fun(char *s[])
{
printf("Entering Fun\n");
printf("s[1]=%s\n",(char *)s[1]);
}
int main(void)
{
char myStrings[2][12];
strcpy(myStrings[0],"7/2/2010");
strcpy(myStrings[1],"hello");
fun(myStrings);
return(0);
}
I got a seg fault when run and the following warning from the compiler:
stackov.c: In function ‘main’:
stackov.c:17: warning: passing argument 1 of ‘fun’ from incompatible pointer type
stackov.c:5: note: expected ‘char **’ but argument is of type ‘char (*)[12]’
However, when I change the main() to the following it works:
int main(void)
{
char myStrings[2][12];
char *newStrings[2];
strcpy(myStrings[0],"7/2/2010");
strcpy(myStrings[1],"hello");
newStrings[0]=myStrings[0];
newStrings[1]=myStrings[1];
fun(newStrings);
return(0);
}
Isn't array[2][12] the same thing as an array of character pointers when it is passed to a function?
No, char array[2][12] is a two-dimensional array (array of arrays). char *array[2] is an array of pointers.
char array[2][12] looks like:
7/2/2010\0\x\x\xhello\0\x\x\x\x\x\x
where \0 is NUL and \x is indeterminate.
while
char *array[2] is:
0x CAFEBABEDEADBEEF
(assuming 32-bit)
The first has 24 contiguous characters, the second has two pointers (to the beginnings of strings elsewhere).
Try
void fun(char s[][12]) { ...}
Read also from the c-faq: My compiler complained when I passed a two-dimensional array to a function expecting a pointer to a pointer
Isn't array[2][12] the same thing as an array of character pointers when it is passed to a function?
No, it is a two-dimensional array. The difference is that an array of pointers contains pointers, but array[2][12] is actually an array of arrays - no pointers involved.
BTW you could do:
char* mystrings[2]={"aha", "haha"};
fun(mystrings);
char myStrings[2][12]; declares myStrings as an array of arrays of characters. This means that myStrings is stored as the 24 bytes
7/2/2010.???hello.??????
‘——————————’‘——————————’
myStrings[0]myStrings[1]
where . represents a null character and ? represents an uninitialized byte.
char *newStrings[2]; declares newStrings as an array of pointers to characters. This means that newStrings is stored as the 2×sizeof(char*) bytes
[..][..]
where [..] represents a pointer object (not yet initialized).
If you want to pass strings of different lengths to your function, you have to pass an array of pointers, not an array of arrays. As you can see above, these are different layouts.
General advice: whenever you're around pointers, draw diagrams (on whiteboard or blackboard if you can, otherwise on paper) showing the various objects in memory, with arrows indicating what is pointing where. There are two kinds of C programmers: the ones who draw such diagrams when they encounter pointers, and the really experienced ones who draw the diagrams in their head.
Your array is declared as a 2-D array, but you want to pass it to the function as though it's a 1-D array of string pointers.
Tom's answer is correct, you can omit the size of the first dimension of multidimensional array declarations for function parameters.
Your second solution works because it explicitly passes a 1-D array of string pointers to the function. Of course, it requires the extra overhead of the array of pointers in addition to the original 2-D string array.
Related
Im completely stuck on how to convert a output from one of my functions of char fileParameters[10][10] into the format of *argv[] to pass into another function that expects the same format of argv. The purpose of this is to pass a file input through the same parser that parses command line input.
I understand argv is a array of pointers but I'm getting confused as aren't all arrays a pointer to the first element?
So therefore fileParameters[10][10] is a pointer to a pointer and if take the address using & then I expected an array of pointers? I've tried everything and whatever I do results in a segfault.
Any nudges in the right direction would be appreciated.
I understand argv is a array of pointers but im getting confused as arent all arrays a pointer to the first element?
No. Arrays can be implicitly converted to a pointer to the first element, but they are not the same thing. You can easily tell by the fact that after char a[10];, sizeof a will give 10 rather than sizeof(char*). Your char[10][10] is an array of arrays, not an array of pointers.
You need to convert your array to an array of pointers:
char fileParameters[10][10];
// ...
char *fileParameterPtrs[10];
for (int i = 0; i != 10; i++)
fileParameterPtrs[i] = fileParameters[i];
and then you can pass fileParameterPtrs to the code that is expecting an array of pointers.
#Vasfed rightly adds that you mentioned "that expects the same format of argv". This doesn't mean just any array of pointers, it means an array of pointers that is terminated by NULL. Your original fileParameters cannot hold any NULL value, so you will need to add one yourself. If all 10 parameters are filled, this is as simple as changing fileParameterPtrs's length to 11 and adding one more assignment. If you have some other way of keeping track of how many fileParameters are used, adjust the code accordingly.
This question already has answers here:
Should I use char** argv or char* argv[]?
(10 answers)
Closed 8 years ago.
I've been fiddling around to see if there's any way to retain information about an array's length automatically when passed into a function (see my other question here: Why is this array size "workaround" giving me a warning?), but my question is more about a warning that gcc is giving that doesn't make sense to me.
According to this website (EDIT: I misread the website), char *p[10] declares a pointer to a 10-wide array of chars. But when I tried to pass in a pointer to an array into a function, I got this error message from the compiler:
Here is the rest of the program:
I know that when an array is passed into a function, it decays into a pointer (losing information about its length), but it seems that the declaration itself is decaying. What's going on here?
EDIT: When I replace the char *p[10] with char (*p)[10], it doesn't give the warning anymore, and more importantly, it displays the proper array length: 10. I guess my questions are 1) Why do the parentheses change things? and 2) Is this a well-known workaround or am I relying on some behavior of the compiler that isn't guaranteed? (i.e. that array length info can be passed by indirectly passing in a pointer to it?)
In fact char *p[10] is an array, of length 10, of pointers to char. You are looking for char (*p)[10]. That is a pointer to an array, of length 10, of char.
You might find http://cdecl.org/ a useful resource to help you test your understanding of declarations.
Regarding the discussion surrounding dynamic arrays, you are going to have to accept that once you allocate an array dynamically, the system provides no means for you to recover the length of the array. It is your responsibility to remember that information.
The subject of your question has been answered already but I wanted to address the heart of it, which is "can I encode the length of an array in its type?" Which is in fact what a pointer-to-array does. The real question is whether you can actually gain any brevity or safety from this. Consider that in each scope where you have a declaration of your type, the length still needs to be known a-priori. To show you what I mean let's generalize your example slightly by making 10 a compile-time constant N.
#define N 10
size_t arraylength(char (*arrayp)[N]) {
return sizeof(*arrayp);
}
int main(void) {
char array[N];
assert( arraylength(&array) == N ); //always true
}
So far so good. We didn't have to pass the length of array anywhere. But it's easy to see that anywhere the expression sizeof(*arrayp) is used, we also could have written N. And any place we declare a char(*)[ ], the bracketed length must come from somewhere.
So what if N isn't a compile time constant, and array is either a VLA or a pointer-to-array from malloc? We can still write and call arraysize, but it looks like this:
size_t arraylength(size_t N, char (*arrayp)[N]) {
return sizeof(*arrayp);
}
int main(void) {
size_t N = length_from_somewhere();
char array[N];
assert( arraylength(sizeof(array), &array) == N );
}
In defining arraysize N must still be visible before the declaration of arrayp. In either case, we can't avoid having N visible outside of the declaration of arrayp. In fact, we didn't gain anything over writing arraysize(size_t N, char* array) and passing array directly (which is a bit silly given the purpose of this function.) Both times arraylength could have equally been written return N;
Which isn't to say that array pointers are useless as parameters to functions -- in the opposite situation, when you want to enforce a length, they can provide type checking to make sure somefunc(char (*)[10]); receives a pointer to an array that is really (sans shady casting) 10 elements long, which is stronger than what a construct like [static 10] provides.
Also keep in mind that all of the length measurements above depend on the underlying type being char where length == size. For any larger type, taking the length requires the usual arithmetic e.g.
sizeof(*arrayp)/sizeof((*arrayp)[0])
In C, arrays decay to pointers to their first elements on most uses. In particular, what a function receives is always just a pointer to the first element, the size of the array is not passed with it.
Get a good text on C and read up on arrays.
I've been fiddling around to see if there's any way to retain information about an array's length automatically when passed into a function
The problem is so annoying that lots of programmers would love to have an answer. Unfortunately, this is not possible.
It seems that the declaration itself is decaying
Pointer to an array is not the same as a pointer to a pointer; that is why you are getting an error.
There is no decaying going on in your code, because you are not passing an array in your code sample: instead, you are trying to pass a pointer to an array &p. The pointer to an array of characters is not compatible to the expected type of the function, which is char**. Array size from the declaration is ignored.
You need to keep in mind two things:
1. Arrays are not pointers.
2. Array names decays to pointers (in most cases) when passed as arguments to functions.
So, when you declare
int a[10]; // a is an array of 10 ints
int *b; // b is a pointer to int
both of a and b are of different types. Former is of type int [10] while latter is of type int *.
In case of function parameter
void foo1 (int a[10]); // Actually you are not passing entire array
void foo2 (int a[]); // And that's why you can omit the first dimension.
void foo3 (int *a); // and the compiler interprets the above two third
ain all of the above function declarations is of same data type int *.
Now in your case
unsigned long arraySize(char *p[10]);
you can declare it as
unsigned long arraySize(char *p[]);
and hence
unsigned long arraySize(char **p);
All are equivalent.
char *p[10] char *p[] and char **p all are exactly equivalent but when they are declared as parameter of a function otherwise char *p[10] (an array of 10 pointers to char) and char **p (a pointer to pointer to char)are entirely of different type.
Suggested reading: C-FAQ: 6. Arrays and Pointers explains this in detailed.
Array name itself is a constant pointer. for example int arr[10]={0};
arr contains the address of arr[0]. hence arr equals&arr[0] .
when u pass the arraysize(&p) , you are actually passing a double pointer .
The correct format to pass a array pointer would be arraysize(&p[0]) or arraysizeof(p)
Note Array name is constant pointer , you cant change its value .
int arr[10];
arr++;
is invalid.
In your case you cant find a size of an array in function by passing the array name . it would return size of pointer(4 or 8 depends on your processor .
The method is to pass the size along with the array
func(array_name , array_size);
These are the notations used for 2D Arrays
char (*names)[5] ;
and
char* names[] = {"Jan","Feb"};
and
char names[3][5] = { Initializers..};
I'm getting extremely confused between these notations.
The 1st one declares names to be a pointer to an array of 5 chars i.e
names -> a char pointer -> "Some string"
The 3rd one has a different memory map, i.e it is stored in row major order like a normal array unlike the one stated above.
How is the 2nd notation similar or different from the 1st and 3rd notation.?
Also passing them to functions is a different story altogether. If we declare the 2d array to be of type 2, then it is passed as a double pointer (char** names) while if it is of type 1 or type 3, the columns should be mentioned in the declaration.
Please help me attain more clarity over these issues.
Thanks.
Only one of those examples is a 2D array:
char names[3][5];
The others are different:
char (*names)[5] ;
is a pointer to a 1D array, and:
char* names[] = {"Jan","Feb"};
is a 1D array of pointers.
I'm going to rename them now to be clearer:
char a[3][5];
char (*b)[5];
char *c[3];
a is the only real two dimensional array. That is, it occupies contiguous memory and has room for three strings, each 5 characters long (including null terminator).
b is a pointer to an array; no storage for any potential contents of that array is included.
c is an array of pointers, each can be used to point to any string you happen to care about; no storage is reserved for any of the strings themselves, just for the three pointers.
If you have a function with a prototype like:
void myfunction(char **p);
Only c can be passed to this function; the others won't behave the way you'd like them to.
gcc 4.6.2 c89
I have the following 2D array that I want to pass to a function:
char elements[MAX_NUM_ELEMENTS][MAX_STRING_LEN] = {{0}};
My function prototype is:
int get_elements(char **elements)
And I am calling the function like this:
get_elements(elements);
However, I get the following error:
expected ‘char **’ but argument is of type ‘char (*)[128]’
All arrays declay into pointers, so sure why I can't just pass the pointer.
Many thanks for any advice,
"All arrays decay into pointers" is a common misconception about C.
The first few answers in this FAQ clarify the issue.
If the object to pass to your function is defined as:
char elements[MAX_NUM_ELEMENTS][MAX_STRING_LEN];
Your function prototype should not be:
int get_elements(char **elements)
but rather:
int get_elements(char elements[][MAX_STRING_LEN])
or
int get_elements(char (*elements)[MAX_STRING_LEN])
(both forms are equivalent)
The reason for this is the type of the value of an object of type
char [MAX_NUM_ELEMENTS][MAX_STRING_LEN]
is
char (*)[MAX_STRING_LEN] (a pointer to an array of MAX_STRING_LEN chars) and not char ** (a pointer to a pointer of char).
You can cast:
get_elements((char **) elements);
char ** and char[128][128] are obviously different types.
"Two -dimensional Array and Double Pointer are not the Same"
"A two - dimensional Array is a array of pointers"
Is what I learnt/memorized while reading about array and pointer
Say elements- data has memory startin Location 100 ..
And the elements Pointer has memory at Location 50 ..
The element data gets allocated memory from 100 to 100+MAX_NUM_ELEMENTS * MAX_STRING_LEN -1..
And you need to access data from 100 ..
But you are passing element as a double pointer .. so it tries to access ( 50->100->Actual data's) Location instead of accessing ( 50-> 100)'s location ..
If you change the prototype to int get_elements( char *element[]) .. It will work ..
Your prototype looks very broken, it lacks a type name.
And you can't use a "decayed" pointer, since that would lose the information about the dimensions of the array, which are (obviously) needed in order to compute accesses properly.
The best way, in my opinion, is to pass a pointer to the first element, along with the dimensions as needed. For 2D, this would do:
int get_elements(int *elements, size_t width, size_t height);
This also requires that you decide, and adhere to, an in-memory layout for your elements, such as column-major or row-major. This affects how you compute the address for a given element.
For the assignment I am working on, I am required to use functions to manipulate data in an array of strings. So really, an array of arrays of chars. I define the array like so:
char strings[5][100];
So there are presumably 500 contiguous chars in memory. The function I have defined looks like this:
void foo(char *labels[100]);
I think I might have some syntax issues here, but what I think this is doing is saying, "I'm a function that expects a pointer to an array of 100 chars." So labels* would point to the first array of chars, and (labels + 1)* would point to the second, and so on. I am calling the function like this:
foo(&strings[0]);
What I think this is doing is grabbing the address of the first array of chars in strings. The error message I'm getting tells me the function expects char ** but the argument is char (*)[100]. This is confusing to me as nowhere did I specify that there be a pointer to a pointer of a char.
Any help is greatly appreciated, or if you could pointer me in the right direction :)
strings is a two dimensional array. So it decays to char(*)[100] when passed to a function. Instead you can have the prototype like -
void foo(char labels[][100], int row); // `row` decides which param to access.
void foo(char labels[][100], int row)
{
for(int i = 0; i < 100; ++i) // If you need, modify all the 100 row elements
{
labels[row][i] = 'a'; // Modifying like this
// ....
}
}
char strings[5][100]
declares strings as an array with 5 elements. Each element is an array of 100 chars.
void foo(char *labels[100]);
declares foo as a function that returns void and accepts an array of pointers. (the 100 is merely decorative: leaving it blank or putting 42 or 10000 is the exact same thing)
You want
void foo(char (*labels)[100]);
where the parameter is a pointer to arrays of exactly 100 chars.