Suppose we want to construct an array of structs, where the definition of the struct cannot be known at compile time.
Here is a SSCCE:
#include <stdlib.h>
int main(int argc, char *argv[]){
if (argc < 3) return 1;
int n = atoi(argv[1]);
int k = atoi(argv[2]);
if ((n < 1) || (k < 1)) return 2;
// define struct dynamically
typedef struct{
int a[n];
short b[k];
}data_point_t;
int m = 10;
// construct array of `m` elements
data_point_t *p = malloc(sizeof(data_point_t)*m);
// do something with the array
for(int i = 0; i < m; ++i) p[i].a[0] = p[i].b[0] = i;
free(p);
return 0;
}
This works fine with gcc (C99), however it doesn't with clang, which yields:
error: fields must have a constant size:
'variable length array in structure' extension will never be supported
So I'm obviously relying on a gcc extension. My question is, how to deal with this kind of problem in standard conform C99? (Bonus question: how to do this in C++11?)
Note: Performance matters, when iterating p there should be aligned memory access. Dereferencing pointers in the loop, yielding random memory access, is not an option.
I think your best bet is to drop the idea of wrapping the array in a structure, bite the bullet and allocate a 2D array yourself.
This will mean that you need to do explicit indexing, but that would have to happen under the hood anyway.
When it comes to alignment, if you're going to visit every n array elements in each of the m arrays, it probably doesn't matter, it's better to make them compact to maximize use of cache.
Something like:
int *array = malloc(m * n * sizeof *array);
Then to index, just do:
// do something with the array
for(int i = 0; i < m; ++i)
{
for(int j = 0; j < n; ++j)
array[i * n + j] = j;
}
If you're very worried about that multiplication, use a temporary pointer. After profiling it, of course.
Sometimes you see this done with a helper macro to do the indexing:
#define INDEX(a, n, i, j) (a)[(i) * (n) + (j)]
then you can write the final line as:
INDEX(array, n, i, j) = j;
it's a bit clumsy since the n needs to go in there all the time, of course.
First of all, it only makes sense to wrap the array inside a struct in the case there are other struct members present. If there are no other struct members, simply allocate an array.
If there are other struct members, then use a flexible array member to achieve what you want. Flexible array members are well-defined in the C standard and will work on every C99 compiler.
// define struct dynamically
typedef struct{
type_t the_reason_you_need_this_to_be_a_struct_and_not_an_array;
int a[]; // flexible array member
}data_point_t;
// construct array of `m` elements
int m = 10;
size_t obj_size = sizeof(data_point_t) + n*sizeof(int);
data_point_t *p = malloc(m * obj_size);
In C++ you can of course use pointers much like you do now, but for a "proper" C++ solution the only viable solution is to use std::vector:
struct data_point_t
{
explicit data_point_t(const size_t sz)
: a(sz) // Construct the vector `a` with `sz` entries,
// each element will be zero initialized (`int()`)
{}
std::vector<int> a;
};
int main(int argc, char *argv[]){
// Read `n`...
int n = 10; // Just example
// Read `m`...
int m = 10; // Just example
// Construct vector of `m` elements
std::vector<data_point_t> p(m, data_point_t(n));
// Here the vector `p` contains `m` elements, where each instance
// have been initialized with a vector `a` with `n` elements
// All fully allocated and initialized
// Do something with the array
// ...
}
This is valid C++03 code, so unless you use something ancient (like Turbo C++) any compiler today should support it.
Related
Im trying to initialize 2d array of chars with this ode
int x=4;
int y=4;
char plg[x][y]={{"o","o","o","o"},{"o","o","o","o"},{"o","o","o","o"},{"o","o","o","o"}};
but this piece of code throws error error: excess elements in char array initializer| i was searching for a while and everything says this is the rigth method how to do 2d char array. Why does it throw error?
In C you cannot use dynamic expressions as array sizes for global variables. It is possible for local variables since the C99 Standard, but these arrays known as VLA cannot be initialized.
For your purpose, you must specify the size directly with literal constants or constant expressions. You can use macros to increase readability, but it is a bad idea to #define x 4 as short identifiers like x may be used elsewhere in your program and will be substituted as well, leading to obscure bugs.
You cannot initialize the 2D array of char with a string for each individual char, you can either use character literals this way:
char plg[4][4] = {
{'o','o','o','o'},
{'o','o','o','o'},
{'o','o','o','o'},
{'o','o','o','o'}
};
Or you can use string literals to initialize the last level of the array:
char plg[4][4] = {"oooo", "oooo", "oooo", "oooo" };
Note that although you can elide the inner braces with char literal initializers this way:
char plg[4][4] = {'o','o','o','o','o','o','o','o','o','o','o','o','o','o','o','o' };
It is not possible to coalesce string initializers this way:
char plg[4][4] = { "oooooooooooooooo" }; // warning: initializer-string for char array is too long
The syntax above only initializes the first subarray with 'o's, leaving the remaining 3 initialized with '\0's
If you really need for the sizes to be dynamic, you will need to initialize the array some other way:
void myfunc(int x, int y) {
char plg[x][y];
int scores[x][y];
// you can initialize char arrays this way
memset(plg, 'o', sizeof(plg));
// you need a loop for other types
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
scores[i][j] = 1;
}
}
...
}
You still need to be careful with this feature: you must check user input a avoid allocating too much data in automatic storage (aka on the stack). Sufficiently large or possibly negative values of x or y will invoke undefined behavior. Only small values should be allowed, typically less than 256. For a more general solution, you will need to allocate plg from the heap.
"this is a string"
and
'o' /* this is a character */
#define N_ROWS 4
#define N_COLS 4
you have to replace " with ' (single) cause it's not string but chars:
char plg[N_ROWS][N_COLS]={{'o','o','o','o'},{'o','o','o','o'},{'o','o','o','o'},{'o','o','o','o'}};
moreover the initializers have to be definied during compile time not during runtime otherwise it would be a dynamic array for which you need to allocate memory manually.
Usually you need to define rows and cols when declaring a matrix, such as:
#define N_ROWS 4
#define N_COLS 4
char plg[N_ROWS][N_COLS]={{'o','o','o','o'},{'o','o','o','o'},{'o','o','o','o'},{'o','o','o','o'}};
Now if you need rows and cols as input variables, you need to dynamically allow the array. For example,
#include <stdlib.h>
#include <string.h>
int x = 4;
int y = 4;
char **plg = malloc(sizeof(char *) * x);
int i = 0;
for( i = 0; i < x; i++ )
{
plg[i] = malloc(sizeof(char) * (y + 1)); // +1 for NULL terminator
}
for( i = 0; i < x; i++ )
{
strcpy( plg[i], "oooo" );
printf( "%s \n", plg[i] );
}
Let's say I have a 9-dimensional array:
int arr[4][4][4][4][4][4][4][4][4];
I want to initialize every element to be 1.
I know I can initialize it using multiple loops:
for(int i1 = 0; i1 < 4; i ++) {
...// eight more similiar loops
}
But it seems ugly.
What is the best practice to do that? Maybe I can use macro?
In C, multidimensional arrays are contiguous, so you can take advantage of this by initializing arr through a pointer.
int* parr = (int*)arr;
for (int i = 0; i < ((sizeof(arr)/sizeof(int)); ++i)
parr[i] = 1;
Note that this won't work in situations where the array decomposes to a pointer (for example, if it was passed to a function as an argument).
write like this:
int *p = &arr[0][0][0][0][0][0][0][0][0];
for( int i = 0; i < 4*4*4*4*4*4*4*4*4; i++)
*p++ = 1;
#nuk because arr is a type
int[4][4][4][4][4][4][4][4][4] // 9 of '[4]'
so
int arr[4][4][4][4][4][4][4][4][4];
sizeof(arr) = sizeof(int[4][4][4][4][4][4][4][4][4]);
= sizeof(int) *4*4*4*4*4*4*4*4*4;
but if you pass a pointer here,
int* arr;
sizeof(arr) = sizeof(int*)
= sizeof(void*)
= Usually the target file's BIT / 8
Maybe use a recursive function which is passed the number levels it needs to initialize.
void init(int * arr, int level, int size, int value)
{
for(int i = 0; i < size; i++)
{
if(level == 0)
arr[i] = value;
else
init(arr[i], level - 1, size, value);
}
}
If you had wanted to initialize to zero, a good old memset would have done it:
int arr[4][4][4][4][4][4][4][4][4];
memset(&arr, 0, sizeof(arr));
That said, however, and since you want to initialize to 1 anyway, I should say that it generally seems like an at least kinda poor idea to use 9D arrays in C. You'll always have to declare that draconian type anywhere you pass it to a function, and you'll never be able to use indirect indexing in any generic way. You're probably better off just declaring a 218 large int-array and calculate the index manually, instead. It's your context, of course, so it's not as if you couldn't have your reasons. :)
I recently started programming C just for fun. I'm a very skilled programmer in C# .NET and Java within the desktop realm, but this is turning out to be a bit too much of a challenge for me.
I am trying to do something as "simple" as returning a two-dimensional array from a function. I've tried researching on the web for this, but it was hard for me to find something that worked.
Here's what I have so far. It doesn't quite return the array, it just populates one. But even that won't compile (I am sure the reasons must be obvious to you, if you're a skilled C programmer).
void new_array (int x[n][n]) {
int i,o;
for (i=0; i<n; i++) {
for (o=0; o<n; o++) {
x[i][o]=(rand() % n)-n/2;
}
}
return x;
}
And usage:
int x[n][n];
new_array(x);
What am I doing wrong? It should be mentioned that n is a constant that has the value 3.
Edit: Here's a compiler error when trying to define the constant: http://i.imgur.com/sa4JkXs.png
C does not treat arrays like most languages; you'll need to understand the following concepts if you want to work with arrays in C.
Except when it is the operand of the sizeof or unary & operator, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array. This result is not an lvalue; it cannot be the target of an assignment, nor can it be an operand to the ++ or -- operators.
This is why you can't define a function to return an array type; the array expression will be converted to a pointer type as part of the return statement, and besides, there's no way to assign the result to another array expression anyway.
Believe it or not, there's a solid technical reason for this; when he was initially developing C, Dennis Ritchie borrowed a lot of concepts from the B programming language. B was a "typeless" language; everything was stored as an unsigned word, or "cell". Memory was seen as a linear array of "cells". When you declared an array as
auto arr[N];
B would set aside N "cells" for the array contents, along with an additional cell bound to arr to store the offset to the first element (basically a pointer, but without any type semantics). Array accesses were defined as *(arr+i); you offset i cells from the address stored in a and dereferenced the result. This worked great for C, until Ritchie started adding struct types to the language. He wanted the contents of the struct to not only describe the data in abstract terms, but to physically represent the bits. The example he used was something like
struct {
int node;
char name[14];
};
He wanted to set aside 2 bytes for the node, immediately followed by 14 bytes for the name element. And he wanted an array of such structures to be laid out such that you had 2 bytes followed by 14 bytes followed by 2 bytes followed by 14 bytes, etc. He couldn't figure out a good way to deal with the array pointer, so he got rid of it entirely. Rather than setting aside storage for the pointer, C simply calculates it from the array expression itself. This is why you can't assign anything to an array expression; there's nothing to assign the value to.
So, how do you return a 2D array from a function?
You don't. You can return a pointer to a 2D array, such as:
T (*func1(int rows))[N]
{
T (*ap)[N] = malloc( sizeof *ap * rows );
return ap;
}
The downside to this approach is that N must be known at compile time.
If you're using a C99 compiler or a C2011 compiler that supports variable-length arrays, you could do something like the following:
void func2( size_t rows, size_t cols, int (**app)[cols] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...; // the parens are necessary
...
}
If you don't have variable-length arrays available, then at least the column dimension must be a compile-time constant:
#define COLS ...
...
void func3( size_t rows, int (**app)[COLS] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...;
}
You can allocate memory piecemeal into something that acts like a 2D array, but the rows won't necessarily be contiguous:
int **func4( size_t rows, size_t cols )
{
int **p = malloc( sizeof *p * rows );
if ( p )
{
for ( size_t i = 0; i < rows; i++ )
{
p[i] = malloc( sizeof *p[i] * cols );
}
}
return p;
}
p is not an array; it points to a series of pointers to int. For all practical purposes, you can use this as though it were a 2D array:
int **arr = foo( rows, cols );
...
arr[i][j] = ...;
printf( "value = %d\n", arr[k][l] );
Note that C doesn't have any garbage collection; you're responsible for cleaning up your own messes. In the first three cases, it's simple:
int (*arr1)[N] = func(rows);
// use arr[i][j];
...
free( arr1 );
int (*arr2)[cols];
func2( rows, cols, &arr2 );
...
free( arr2 );
int (*arr3)[N];
func3( rows, &arr3 );
...
free( arr3 );
In the last case, since you did a two-step allocation, you need to do a two-step deallocation:
int **arr4 = func4( rows, cols );
...
for (i = 0; i < rows; i++ )
free( arr4[i] )
free( arr4)
Your function return void, so the return x; line is superfluous. Aside from that, your code looks fine. That is, assuming you have #define n 3 someplace and not something like const int n = 3;.
You can't return an array in C, multidimensional or otherwise.
The main reason for this is that the language says you can't. Another reason would be that generally local arrays are allocated on the stack, and consequently deallocated when the function returns, so it wouldn't make sense to return them.
Passing a pointer to the array in and modifying it is generally the way to go.
To return (a pointer to) a newly-created array of dimensions known at compile time, you can do this:
#define n 10 // Or other size.
int (*new_array(void))[n]
{
int (*x)[n] = malloc(n * sizeof *x);
if (!result)
HandleErrorHere;
for (int i = 0; i < n; ++i)
for (int o = 0; i < n; ++o)
x[i][o] = InitialValues;
return x;
}
…
// In the calling function:
int (*x)[n] = new_array();
…
// When done with the array:
free(x);
If the size is not known at compile time, you cannot even return a pointer to an array. C does support variable-length arrays but not in the return types of functions. You could instead return a pointer to a variable-length array through a parameter. That requires using a parameter that is a pointer to a pointer to an array of variable length, so it gets somewhat messy.
Also, the preferred choices between allocating an array in the caller dynamically, allocating an array in the caller automatically, allocating an array in the called function dynamically and using variable-lengths arrays or fixed-length arrays or even one-dimensional arrays with manual indexing depend on context, including what how large the array might be, how long it will live, and what operations you intend to use it for. So you would need to provide additional guidance before a specific recommendation could be made.
In C there's only pass/return by value (no pass by reference). Thus the only way of passing the array (by value) is to pass its address to the function, so that it can manipulate it through a pointer.
However, returning by value an array's address isn't possible, since by the time control reaches the caller, the function goes out of scope and its automatic variables go down with it too. Hence if you really have to, you can dynamically allocate the array, populate and return it, but the preferred method is passing the array and leaving the onus of maintaining the array to the caller.
As for the error, the only warning I get in GCC for this is warning: 'return' with a value, in function returning void which is simply meaning that you shouldn't return anything from a void function.
void new_array (int x[n][n]); what you're really doing here is taking a pointer to an array of n integers; the decayed type is int (*x)[n]. This happens because arrays decay into pointers generally. If you know n at compile time, perhaps the best way to pass is:
#define n 3
void new_array (int (*x)[n][n]) {
int i,o;
for (i=0; i<n; i++) {
for (o=0; o<n; o++) {
x[i][o]=(rand() % n)-n/2;
}
}
}
And call it as
int arr[n][n];
new_array(&arr);
You can pass around arbitrarily dimensions arrays like any another variable if you wrap them up in a struct:
#include <stdio.h>
#define n 3
struct S {
int a[n][n];
};
static struct S make_s(void)
{
struct S s;
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
s.a[i][j] = i + j;
}
return s;
}
static void print_s(struct S s)
{
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
printf(" %d", s.a[i][j]);
printf("\n");
}
}
int main(void) {
struct S s;
s = make_s();
print_s(s);
return 0;
}
You are probably declaring n as a constant integer:
const int n = 3;
Instead, you should define n as a preprocessor definition:
#define n 3
Is it possible to write a function which accept 2-d array when the width is not known at compile time?
A detailed description will be greatly appreciated.
You can't pass a raw two-dimensional array because the routine won't know how to index a particular element. The 2D array is really one contiguous memory segment.
When you write x[a][b] (when x is a 2d array), the compiler knows to look at the address (x + a * width + b). It can't know how to address the particular element if you don't tell it the width.
As an example, check http://www.dfstermole.net/OAC/harray2.html#offset (which has a table showing how to find the linear index for each element in an int[5][4])
There are two ways to work around the limitation:
1) Make your program work with pointer-to-pointers (char *). This is not the same as char[][]. A char * is really one memory segment, with each value being a memory address to another memory segment.
2) Pass a 1d pointer, and do the referencing yourself. Your function would then have to take a "width" parameter, and you could use the aforementioned formula to reference a particular point
To give a code example:
#include <stdio.h>
int get2(int *x) { return x[2]; }
int main() {
int y[2][2] = {{11,12},{21,22}};
printf("%d\n", get2((int *)y));
}
This should print out 21, since y is laid out as { 11, 12, 21, 22 } in memory.
C supports variable-length arrays. You must specify the width from a value known at run-time, which may be an earlier parameter in the function declaration:
void foo(size_t width, int array[][width]);
One way is use the good old "pointer to array of pointers to arrays" trick coupled with a single continuous allocation:
/* Another allocation function
--------------------------- */
double ** AnotherAlloc2DTable(
size_t size1, /*[in] Nb of lines */
size_t size2 /*[in] Nb of values per line */
)
{
double ** ppValues;
size_t const size1x2 = size1*size2;
if(size1x2 / size2 != size1)
return NULL; /*size overflow*/
ppValues = malloc(sizeof(*ppValues)*size1);
if(ppValues != NULL)
{
double * pValues = malloc(sizeof(*pValues)*size1x2);
if(pValues != NULL)
{
size_t i;
/* Assign all pointers */
for(i=0 ; i<size1 ; ++i)
ppValues[i] = pValues + (i*size2);
}
else
{
/* Second allocation failed, free the first one */
free(ppValues), ppValues=NULL;
}
}/*if*/
return ppValues;
}
/* Another destruction function
---------------------------- */
void AnotherFree2DTable(double **ppValues)
{
if(ppValues != NULL)
{
free(ppValues[0]);
free(ppValues);
}
}
Then all you have to do is pass a char ** to your function. The matrix is continuous, and usable as mat[x][y].
Possible accessor functions:
int get_multi(int rows, int cols, int matrix[][cols], int i, int j)
{
return matrix[i][j];
}
int get_flat(int rows, int cols, int matrix[], int i, int j)
{
return matrix[i * cols + j];
}
int get_ptr(int rows, int cols, int *matrix[], int i, int j)
{
return matrix[i][j];
}
An actual multi-dimensional array and a fake one:
int m_multi[5][7];
int m_flat[5 * 7];
Well-defined ways to use the accessor functions:
get_multi(5, 7, m_multi, 4, 2);
get_flat(5, 7, m_flat, 4, 2);
{
int *m_ptr[5];
for(int i = 0; i < 5; ++i)
m_ptr[i] = m_multi[i];
get_ptr(5, 7, m_ptr, 4, 2);
}
{
int *m_ptr[5];
for(int i = 0; i < 5; ++i)
m_ptr[i] = &m_flat[i * 7];
get_ptr(5, 7, m_ptr, 4, 2);
}
Technically undefined usage that works in practice:
get(5, 7, (int *)m_multi, 4, 2);
[Warning - this answer addresses the case where the number of columns - the WIDTH - is known]
When working with 2D arrays, the compiler needs to know the number of columns in your array in order to compute indexing. For instance, if you want a pointer p that points to a range of memory to be treated as a two-dimensional set of values, the compiler cannot do the necessary indexing arithmetic unless it knows how much space is occupied by each row of the array.
Things become clearer with a concrete example, such as the one below. Here, the pointer p is passed in as a pointer to a one-dimensional range of memory. You - the programmer - know that it makes sense to treat this as a 2D array and you also know (must know) how many columns are there in this array. Armed with this knowledge, you can write code to create q, that is treated by the compiler as a 2D array with an unknown number of rows, where each row has exactly NB columns.
I usually employ this when I want the compiler to do all the indexing arithmetic (why do it by hand when the compiler can do it?). In the past, I've found this construct to be useful to carry out 2D transposes from one shape to another - note though that generalized 2D transposes that transpose an MxN array into an NxM array are rather beastly.
void
WorkAs2D (double *p)
{
double (*q)[NB] = (double (*)[NB]) p;
for (uint32_t i = 0; i < NB; i++)
{
for (uint32_t j = 0; j < ZZZ; j++) /* For as many rows as you have in your 2D array */
q[j][i] = ...
}
}
I believe a nice solution would be the use of structures.
So I have an example for 1d-Arrays:
Definition of the struct:
struct ArrayNumber {
unsigned char *array;
int size;
};
Definition of a function:
struct ArrayNumber calcMultiply(struct ArrayNumber nra, struct ArrayNumber nrb);
Init the struct:
struct ArrayNumber rs;
rs.array = malloc(1);
rs.array[0] = 0;
rs.size = 1;
//and adding some size:
rs.size++;
rs.array = realloc(rs.array, rs.size);
hope this could be a solution for you. Just got to change to a 2d Array.
I want to scan a 2D array with the help of pointers and have written this code, could you tell me why the compiler gives errors?
#include<stdio.h>
#include<stdlib.h>
int main(void) {
int i,j,n,a,b;
int (*(*p)[])[];
printf("\n\tEnter the size of the matrix in the form aXb\t\n");
scanf("%dX%d",&a,&b);
p=(int (*(*p)[b])[a])malloc(b*sizeof(int (*p)[a]));
for(i=0;i<b;i++) {
p[i]=(int (*p)[a])malloc(a*sizeof(int));
printf("\t\bEnter Column %d\t\n");
for(j=0;j<a;j++)
scanf("%d",&p[i][j]);
}
return 0;
}
This statement has several problems:
p=(int (*(*p)[b])[a])malloc(b*sizeof(int (*p)[a]));
First, malloc returns a void*. You are casting that pointer using (int (*(*p)[b])[a]) which yields a value, not a data type. That isn't a valid cast, so that's one reason that the compiler is yelling at you. At this point, p hasn't been initialized so the de-referencing taking place here can crash your program if this statement was executed.
Inside your malloc call, you are using sizeof(int (*p)[a]). The statement int (*p)[a] isn't a valid C statement.
It seems that you are making this a bit more complex that it needs to be. There are two ways of building a 2D array. You can build an array using malloc(a * b * sizeof(int)) as Reinderien explains. You can also build a 1D array of pointers, each pointing to an array of type int. From your code, it seems you are trying to do the latter.
The easier way to do this would be something like this:
int **p;
... get input from user ...
// Declare an array of int pointers of length b
p = malloc(b * sizeof(int*));
// For each int* in 'p' ...
for (i = 0; i < b; ++i) {
// ... allocate an int array of length 'a' and store a pointer in 'p[i]' ..
p[i] = malloc(a * sizeof(int));
// ... and fill in that array using data from the user
printf("\t\bEnter Column %d\t\n");
for(j = 0; j < a; j++)
scanf("%d", &p[i][j]);
}
Using this method of building a 2D array allows you to use the syntax p[x][y]. Since p is a pointer-to-pointer, p[x] is a pointer to an array and p[x][y] is an item in the pointed-to array.
That's some pretty contorted syntax. Usually when you make a 2D array:
The declaration is simply int *p;
The allocation is simply p = malloc(a*b*sizeof(int));
You cannot write p[i][j]. You must do one of several things - either make a secondary array int **q that contains row pointers to be able to write q[i][j] (better performance and legibility), or write p[b*i + j] (fewer steps).
Additionally, note that:
Your printf will spew garbage due to the missing %d parameter.
Since C is not typesafe, using scanf will hide any errors in indirection that you may make.
About the closest thing I could think of that remotely resembles what you were trying to do:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j;
const int a = 3, b = 4;
int m[4][3];
int (*p[4])[3];
for (i = 0; i < b; i++)
{
p[i] = &m[i];
printf("\t\bEnter Column %d\t\n", i);
for (j = 0; j < a; j++)
{
int x;
scanf("%d", &x);
(*p[i])[j] = x;
}
}
return 0;
}
It compiles and functions as expected, but it's pointlessly complicated. p is an array of pointers to arrays.