Array declaration - c

Consider the following declaration:
char *name[]={"John","Beckham"};
Is this considered as 2D Array or not?
Because my professor told me that it's not 2D array but something else,
and if yes ..we can say that we can declare 2D array without specifying dimensions.

It is an array of char*. It's length is 2. The first element is a pointer which points to the string literal "John", and the second is a pointer which points to the string literal "Beckham".
The entire structure is two-dimensional, in the sense that two numbers specify the location of one of the char elements (for example, the character 'k' is located at (1,3)). But it is not rectangular, so it does not have a simple size like [2, 7] (since there is no (0,4) element). It is not what people usually refer to when they talk about a "two-dimensional array".

Of course your professor is right. An array named Arr of type T might look like
T Arr [] = { ... };
In this case, T is the type char *, and the brackets [] denote an array of char *s.
The difference relies on the fact that a pointer is not an array.
See the C FAQ for information on the differences.

Related

Is there a way to use zero-length arrays with 2d arrays?

I just discovered zero-length arrays and I'd like to use it for a 2d array, the advantage of these arrays is to avoid pointers inside a structure so we can just free the structure instead of having to free it's data, so it can better be used inside a container structure like a linked list for example without having to pass a destructor function, but the problem is I can't figure out how to use it for 2d arrays. I have a structure looking like this:
struct s_arg
{
int argc;
char argv[0][0];
};
But the problem is: how to keep track of each member size without another array containing sizes? Is this possible to do this with no malloc for struct members ?
No.
The only reason an array can be used with no size known is because you do not need to know the size in order to access elements. Given an array a, a[0] is at the start of the array, a[1] is one element beyond that, and so on. The location of any element a[i] can be computed without knowing the size of the array.
Naturally, for an array to exist, somebody has to allocate memory for it, and so they must know the size. So the creator of an array must know its size, but the user does not need to.
GCC allows zero-length arrays as an extension so that a structure can have an array at its end, where the memory is allocated by the creator of the structure, who knows its size. Except to support old software, this extension became unnecessary once the C standard supported arrays of unknown size (declared with no size, [], called flexible array members).
For two-dimensional arrays, the ability to use an array without knowing its size does not apply. Given a two-dimensional array of char named a, a[i][j] is located j elements after the start of a[i]. Each of those elements is a char, so calculating j char beyond a[i] is easy. And a[i] starts i elements after the start of a. But the elements of a are arrays of char. To know how big i elements is, you must know the size of the element; you must know the size of the array of char.
So a two-dimensional array cannot be used unless the size of the second dimension is known.
There are ways to use a two-dimensional array whose second-dimension size is known at run-time, including:
Use a one-dimensional array and calculating indices into it manually, as with a[i*size + j].
Use a one-dimensional array and convert its address. For example, from some structure s with member m, (char (*)[size]) s.m, which can then be used as ((char (*)[size]) s.m)[i][j]. (See other Stack Overflow questions and answers for language-lawyer issues about treating one-dimensional arrays as two-dimensional arrays.)
Also, your member name argv suggests you might want this structure to store command-line arguments passed as a parameter of main. If so, you should be mindful that the argv second parameter of main is a pointer to pointers, not a pointer to an array. The data in those strings is generally not arranged in memory for use as a two-dimensional array of char. You could copy the strings into a two-dimensional array, but that would generally be wasteful.

Pointers to Character Array

So I am in the process of learning C and am slightly confused by this statement on the website I am learning from.
if you have
char ch_arr[3][10] = {
"spike",
"tom",
"jerry"
};
It says that.
The ch_arr is a pointer to an array of 10 characters or int(*)[10]
However, what is the meaning of int(*)[10], if this is a character array, why is the pointer not a char type?
Thanks in advance, sorry if the question is bad, I'm trying to get better at asking questions.
This is a two-dimensional array. Each string (e.g. "spike") is a character array. That means that it's basically an array containing arrays.
char ch_arr[3][10] = {"spike", "tom", "jerry"};
The two-dimensional array ch_arr can then be converted to a pointer. In both C and C++ array to pointer conversion applies to every array automatically on access, so the pointer points to the first element, which is of type char[10] in this case. Therefore the pointer is of type char(*)[10], as Keith Thoumpson pointed out in the comments.
And concerning the website you are using... It contains some mistakes, so I would use a different source instead.

Array pointer from C to D

I'm using D and interfacing with some C libraries. As a result I have to convert D arrays to pointers for C (ex. short*). Currently I just cast them like this:
int[] dArray = [0, 1, 2, 3, 4];
myCFunction(cast(int*) dArray);
Is this unsafe? I tried to do:
myCFunction(&dArray);
But doing that gives the function an int[]* instead of int*. I see that in C++ some people take the first element like this:
myCFunction(&dArray[0]);
But wouldn't that pointer only point to the first element? I am new to pointers and references as I have come from the world of Java.
How would I convert an array to a pointer so I can pass it to a C function?
In D, an array is actually (conceptually) this:
struct {
size_t length;
void* ptr;
};
The usual way of getting a pointer from an array is to use the .ptr field. In your case: myCFunction(dArray.ptr);
But wouldn't that pointer only point to the first element
Because the elements are stored contiguously in memory, a pointer to the first element is all we need. We just add an offset to that pointer if we want to get the addresses of other elements.
One other point: usually if a C function wants an array pointer, it also has an argument for the array length. In most cases you can give it dArray.length, but sometimes it's actually asking for the size in bytes, rather than the number of elements.

Two dimensional array address and corresponding pointer to its 1st element

In terms of one dimensional array, its array name is also the address of the first element. So it is fine to assign it to a pointer, like below:
char data[5];
char* p_data=data;
So I think it should be the same with two dimensional array. The array name should be the address of the first element's address. So, I'd like to do something like this:
char data[5][5];
char** pp_data=data;
Then I get a warning saying the pointer type char** is incompatible with char[ ][ ].
Why does this happen? Do I comprehend the pointer and array concept wrong?
You're right that an array is often referred to by a pointer to its first element. But when you have the "two dimensional" array
char data[5][5];
what you actually have is an array of arrays. The first element of the array data is an array of 5 characters. So this code would work:
char (*pa_data)[5] = data;
Here pa_data is a pointer to array. The compiler won't complain about it, but it may or may not actually be useful to you.
It's true that a pointer-to-pointer like your char **pp_data can be made to act like a two-dimensional array, but you have to do some memory allocation for it to work. It turns out that in the array-of-arrays char data[5][5] there's no pointer-to-char for pp_data to be a pointer to. (In particular, you could not say something like pp_data = &data[0][0].)
See also this question in the C FAQ list.
Two dimensional array is actually an array of arrays. It means the first element of that array is an array. Therefore a two dimensional array will be converted to pointer to an array (its first element).
In
char data[5][5];
when used in expression, wit some exception, data will be converted to pointer to its first element data[0].data[0] is an array of char. Therefore the type of data will become pointer to an array of 5 char, i.e. char (*)[5].
char ** and char (*)[5] are of different type, i.e. incompatible type.

Different pointer notations in 2D Arrays?

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.

Resources