How to reach an array that an array of pointers points to? - arrays

I'm trying to create an array of pointers, in which each pointer points to the start of an array (which is basically also an array of pointers)
I've tried the following:
//declarations:
int* all_paths_of_size_r= (int*)malloc(p_num*sizeof(int)); //p_num is the number of possible paths of size r
int* path = (int*)malloc(r*sizeof(int));
I'm using both of them in recurrsive function in which i wrote:
*(all_paths_of_size_r + place_in_arr) = path[0];
free(path);
place_in_arr++;
adds++; // this is an int that tells me if there are no more possible paths of size r so that i can free the last malloc I created within the function
int* path = (int*)malloc(r*sizeof(int));
if(adds==how_many_paths_of_size_r_could_be_generated_of_set_N(r, N)) //set N is the numbers from 0 to N-1
free(path);
now, I'm trying to reach each one of these arrays that are pointed at by all_paths_of_size_r (I mean I’m trying to reach every array to check if the last number of it is x), how do I do so?

Related

In C, why does the second dimension of a 2D array parameter need to specified in the function definition? [duplicate]

This question already has answers here:
Why do we need to specify the column size when passing a 2D array as a parameter?
(8 answers)
Closed 12 months ago.
As part of a small C program I've written, I have an insertion sort function that inserts a given string into a given array in its sorted location. I've gotten the function to work, but I'm wondering why I need to specify the second dimension for the array in the function definition to keep from getting a compilation time error. In my function, if I leave out the LONGEST_WORD macro, I get an "array has incomplete element type 'char []'" error when compiling. Everything runs smoothly when I keep it in. Could someone please explain why? Thank you!
#include <string.h>
int insertInOrder(char array[][LONGEST_WORD], char* word, int wordCount) {
int i, j, location = wordCount;
/* finds index of location to insert word; */
for (i = 0; i < wordCount; i++) {
if (strcmp(word, array[i]) <= 0) {
location = i;
break;
}
}
/* makes space for new word to be inserted, shifting all words greater than word to the right by one */
for (j = wordCount; j > location; j--) strcpy(array[j], array[j-1]);
strcpy(array[location], word); /* copies new word to its location */
return 0;
}
C is concerned with the actual memory size of your array. char array[][LONGEST_WORD] is an array of arrays of char that are LONGEST_WORD in length.
Knowing this, the compiler knows that array[n+1] is LONGEST_WORD bytes past the address of array[n].
If you hadn't specified this, it doesn't know how to address elements in that array.
A "2D array" is nothing more than a 1D array of 1D arrays.
To find the address of an element in a 1D array the compiler needs to know the address of the array and the size of an element (e.g. for uint32_t myArray[10];, to find the address of myArray[i] C does something like address = (void *)myArray + i * sizeof(uint32_t)).
To find the address of an element in a 1D array (of 1D arrays) the compiler needs to know the address and the size of an element, and the size of the outer array's elements is the size of a whole inner 1D array which depends on its type and how many elements the inner array has.
E.g. for uint32_t myArray[20][10];, to find the address of myArray[i] C does something like address = (void *)myArray + i * sizeof(uint32_t innerArray[10])); and to find the address of myArray[i][j] C does something like outerAddress = (void *)myArray + i * sizeof(uint32_t innerArray[10]) and then does innerAddress = outerAddress + j * sizeof(uint32_t). Of course this can (and normally would) be simplified into innerAddress = (void *)myArray + (i * 10 + j) * sizeof(uint32_t).
if I leave out the LONGEST_WORD macro, I get an "array has incomplete element type"
Yes. Essentially, the outer 1D array is a 1D array of "incomplete element type" elements; and not a 1D array of "1D array of LONGEST_WORD chars" elements.

Typedef to a double array of ints

I am trying to learn about an implementation of some code that uses a typedef to a double array and also uses pointers and I am having some difficulty understanding the code and details on how the code works and what types the variables are and what points to what.
I have tried playing around with different implementations and trying to understand how it works but the results I have gotten have been not what I have expected.
Heres some code I tried to test:
typedef int array[2][6];
array *arr;
arr = (array*)malloc(sizeof(array));
*arr[0][0]=2;
*arr[0][1]=4;
*arr[1][0]=3;
*arr[1][1]=5;
printf("line 1: %d %d\nline 2: %d %d\n",*arr[0][0],*arr[1][0],*arr[0][1],*arr[1][1]);
int *in = (int*) ((*arr)[0]);
printf("in = %d\n",in[1]); // results are unexpected
The code that I am actually looking at is for a ping pong buffer and is (simplified) as follows:
int buffer_count = 2; // 2 ping pong buffers
int sample_size = 15;
typedef int PingPong_t[buffer_count][sample_size];
PingPong_t *inputstream;
// logic goes here to determine pingpong_idx
int pingpong_idx = 0; // I believe this is to choose the first or second buffer
int *pcmIn = (int*)((*inputstream)[pingpong_idx]);
// do processing
I expect that pcmIn is an integer array of the current ping or pong buffer, but I am having trouble proving that to myself or I am just unsure what the datatypes actually are and what it is actually doing.
A good question I might have is, what is the type of inputstream? Is it correct to say that inputstream is a pointer to a double array of integers? Or is inputstream a double array of integer pointers?
Then what would be the type of pcmIn?
Let's break it down.
typedef int PingPong_t[buffer_count][sample_size];
This will make PingPong_t represent a 2D array of integers.
So, you can have
PingPong_t p = {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},{3,4,5,6,7,8,9,10,11,12,13,14,15,16,17}};
Then, we declare a pointer to this type as
PingPong_t *inputstream;
which means that inputstream is a pointer to whatever PingPong_t represents. It is not an array, not an array of pointers, just a pointer.
Since PingPong_t essentially means int x[2][15], inpustream will mean int (*y)[2][15].
Suppose we had something like
inputstream = &p;
Then, inputstream will point to the 2D array that is p. A custom pointer of type 2-dimensional (2 x 15) int array.
So, inputstream is int (*)[2][15] and p is int [2][15].
Now, playing it further, let us suppose we were to increment inputstream.
Incrementing a pointer will add the size of the type it points to.
So, in our case incrementing inpustream adds sizeof(int)*2*15 i.e. 120 (my machine has 4-byte int). Note that it does not add sizeof(int) here as its base type is not int but a 2D array of ints.
Finally, pcmIn is an int pointer (which can be thought of as a 1D array here), we are assigning like this
int *pcmIn = (int*)((*inputstream)[pingpong_idx]);
which fetches the first row (pingpong_idx) of the 2D array that inputstream points to, and assigns it to pcmIn.
Furthermore, you are getting unexpected results in your example above as you are assigning to the array in wrong manner. Since arr is a pointer to 2D array, you assign a value to an element like this
(*arr)[0][1]=4;
and not like this
*arr[0][1]=4;.
The latter will mean that arr is a 2D array of pointers and you are basically setting the value of [0][1]th pointer to 4, which is not what you had planned.
arr is not a 2D array and so arr[0][1] will mean the adding sizeof(int)*15 to the value of arr, and *arr[0][1] is basically getting/setting value at that address. In effect, the [0][1]th value is still uninitialized.
But, then how does *arr[0][0]=2; and printf("in = %d\n",in[0]); work?
Because, doing *arr[0][0]=2; will set the value of [0][0]th element to 2.

Dynamically expanding array of structs C [duplicate]

This question already has answers here:
Dynamic array in C — Is my understanding of malloc and realloc correct?
(3 answers)
Closed 5 years ago.
So for my school project, a large CSV file will be entered through stdin and we will have to sort it based on column and print it out as a sorted csv file.
The step I am on right now is figuring out how to keep reallocing a struct of arrays so that it will grow if there is not big enough to hold the data coming in from stdin. We don't know the exact amount of rows that will be inputted in the CSV file. Right now we just used a static amount to test and see if the values are assigned to the structs.
I am still a beginner at C so I do not clearly know how I would iterate through a pointer like I would iterate through an array. Since we are using a static amount of structs in the array, we can just iterate using array[i] like in Java but how would you iterate through something like *array?
I do not know where to start for creating this dynamic array. I tried
struct array* testArray = (array*)malloc(sizeof(testArray));
but I have no idea how to iterate through it like I did with the static array by using array[i].
Any help would be greatly appreciated, sorry for the wall of text...
You can navigate through a malloced space the same way as with an array (using indicies), but it seems that your main issue lies in your use of malloc. Malloc's argument is the size in number of bytes that you want to allocate. So if you want to have an array of structs, you would first need to find out how many bytes one struct contains using sizeof(struct array), and then determine how large of an array you want, let's say N. So that line of code should look more like struct array* testArray = malloc(N * sizeof(struct array));. The return value of malloc will be a void pointer containing the memory address of the first byte of allocated space. Upon assigning this value to testArray, it will be type-casted to the assigned variable type (struct array *). Now you can use pointer arithmetic to access a specific index i with *(testArray + i), or simply testArray[i]. If you find that N was not a sufficient size, you can use realloc to increase the array size to 2N, or whatever size deemed necessary.
struct array* testArray = (array*)malloc(sizeof(testArray));
is a little wrong as you only allocate 1 element of testArray.
It is more like:
struct A
{
int a;
int b;
....
};
struct A* arr = malloc( N * sizeof(struct A) );
^^^
N element of struct A
int j;
for (j=0; j<N; ++j) // Iterate it like any other array
{
arr[j].a = 5;
arr[j].b = 42;
....
}
Use realloc when you need the array to grow.
When reading from a file/stdin it could look like (based on comment from David C. Rankin):
int n=0; // Count of the number of structs read from the file
struct A* arr = malloc( N * sizeof(struct A) );
while (read line from file)
{
arr[n].a = val1;
arr[n].b = val2;
++n; // Increment count
if (n == N) // Check if current array is full, i.e. realloc needed
{
// realloc array to 2 * N; N = N * 2
}
}

Fast way to copy an array

So at the end of each iteration that I'm doing, I want to make my array be equal to my new array (which I have called array_new). I want every element of array to take the same value as is in array_new but I'm interested in getting my code as quick as possible and so copying everything across element-by-element as this current code does isn't an option:
for(i=0;i<N_a;i++) {
for(j=0;j<N_b;j++) {
array[i][j] = array_new[i][j];
}
}
This takes quite a long time because my values of N_a and N_b are very large. Is there a way to simply change what each of them point to so that I can start my next iteration more quickly? I've tried doing stuff like
double *temp = *array;
*array = *array_new;
*array_new = temp;
in order to try and avoid a slow element-by-element copying procedure but it doesn't seem to work for me. Effectively what I'm trying to make happen is for every element of array point to the corresponding element in array_new but I can't work out how to make the pointers do that.
Any help would be much appreciated!
Since the memory size of your array is fixed, you can simply copy the memory block from one pointer to the other. It doesn't get any faster than that.
In c/c++ you could use memcpy if that is the language you are using. Every language has something equivalent.
Edit: since you confirmed use of c I can get more detailed:
memcpy(array_new,array,sizeof(VARIABLE_TYPE_of_ARRAY_ELEMENT)*N_a*N_b);
Your pointer-swap code is just a little bit off: you are dereferencing your pointers where you shouldn't. After all, the point of that code is to avoid copying data by just swapping two pointers. Here are the correct versions (depending on whether you use a true 2D array or an array of pointers to arrays):
//array is declared as
double (*array)[N_b];
double (*temp)[N_b] = array;
array = array_new;
array_new = temp;
or
//array is declared as
double** array;
double** temp = array;
array = array_new;
array_new = temp;
This is all you need, and it's definitely the fastest possible way to exchange contents of two buffers. Much faster than memcpy()...
If you just want to swap the pointers, not physically copying the data, and to still be able to access the arrays using indexes, here is an example of how it can be done:
#define N_a 2
#define N_b 3
typedef struct arr
{
int val[N_a][N_b];
} arr;
arr array = {{{11,12,13},{14,15,16}}};
arr array_new = {{{21,22,23},{24,25,26}}};
int main()
{
arr *p_array;
arr *p_array_new;
p_array = &array;
p_array_new = &array_new;
printf("%d %d\n", p_array->val[1][2], p_array_new->val[1][2]);
// output: 16 26
p_array = &array_new;
p_array_new = &array;
printf("%d %d\n", p_array->val[1][2], p_array_new->val[1][2]);
// output: 26 16
}
Two answer this, you first need to understand how the array is represented in memory. E.g. see this question: How are multi-dimensional arrays formatted in memory?
So first we need to know if you have a static array or not. If it is a static array then the task is particularly simple, because the data is laid out contiguously in memory. This means that if you have a 2x2 static array, with the content {{9, 8}, {7, 6}} your memory could look like this:
Address 0 1 2 3 4 5 6 7 8
Content ? ? 9 8 7 6 ? ? ?
In this case your variable which is declared like this:
int[2][2] myArray;
is actually a pointer to address "2" and you can easily copy the whole thing. with memcpy:
int [2][2] newArray;
memcpy(&newArray, &myArray, sizeof(int)*2*2);
Notice that this copies starting from wherever "myArray" points (in my example that is 2) as many bytes as 2*2*sizeof(int). So 4 times the size of int. (For simplicity my example assume a size of one byte for an int, but of course on most systems it is 4 byte).
If you have a dynamic array, then it is a different story. In this case your memory for your array declared like this:
int** myArray;
may well look like this:
Address 0 1 2 3 4 5 6 7 8
Content 9 8 0 6 ? ? 7 6 ?
Note that the pointer myArray still points to the Address "2". However at the address "2" you don't find the first value, but instead another pointer which points to "0". And here you find the values of the first "row" which are 9 and 8.
Next to the address "2" in number "3" you find the pointer to your second "row" which starts at position 6. As you can see, you can still find all your data, but you cannot copy them in a single go. To copy the whole array you will at least need the outer row:
int SIZE_X = 2;
int SIZE_Y = 2;
int** newArray = malloc(sizeof(int*)*SIZE_X);
for(i = 0; i < SIZE_X; ++i) {
newArray[i] = malloc(sizeof(int)*SIZE_Y);
memcpy(newArray[i], myArray, SIZE_Y*sizeof(int));
}
This should be faster then using two loops, as memcpy can use more efficient ways to copy than a copy loop.

initialize a global 2-dimensional C array of integers at run time

I need to store an array of point (x,y). I read the points from a file, and the number of points are not constant, but i can get it at the first line of the file. So i write a procedure load() to loading the points from the file and store them in a global array. It doesn't work.
My code:
int *array[][]; // this is a pointer to a 2-dimensional array??
void load(){
..
int tempArray[2][n]; //n is the first line of the file
..
array = tempArray;
}
You're trying to return a pointer to memory that is local to the function that defines the variable. Once that function stops running ("goes out of scope"), that memory is re-used for something else, so it's illegal to try and reference it later.
You should look into dynamic allocation, and have the loading function allocate the needed memory and return it.
The function prototype could be:
int * read_points(const char *filename, size_t *num_points);
Where filename is of course the name of the file to open, num_points is set to the number of points found, and the returned value is a pointer to an array holding x and y values, interleaved. So this would print the coordinates of the first point loaded:
size_t num_points;
int *points;
if((points = load_points("my_points.txt", &num_points)) != NULL)
{
if(num_points > 0)
printf("the first point is (%d,%d)\n", points[0], points[1]);
free(points);
}
This declaration of yours does not work:
int *array[][]; // this is a pointer to a 2-dimensional array??
First, it is trying to declare a 2D array of int *. Second, when you declare or define an array, all dimensions except the first must be specified (sized).
int (*array)[][2]; // This is a pointer to a 2D array of unknown size
This could now be used in a major variant of your function. It's a variant because I misread your question at first.
void load(void)
{
...
int tempArray[n][2]; // Note the reversed order of dimensions!
...
array = &tempArray;
...there must be some code here calling functions that use array...
array = 0;
}
Note that the assignment requires the & on the array name. In the other functions, you'd need to write:
n = (*array)[i][j];
Note, too, that assigning the address of a local array to a global variable is dangerous. Once the function load() returns, the storage space for tempArray is no longer valid. Hence, the only safe way to make the assignment is to then call functions that reference the global variable, and then to reset the global before exiting the function. (Or, at least, recognize that the value is invalid. But setting it to zero - a null pointer - will more nearly ensure that the program crashes, rather than just accessing random memory.
Alternatively, you need to get into dynamic memory allocation for the array.
Your question actually is wanting to make a global pointer to a VLA, variable-length array, where the variable dimension is not the first:
int tempArray[2][n]; // Note the reversed order of dimensions!
You simply can't create a global pointer to such an array.
So, there are multiple problems:
Notation for pointers to arrays
Initializing pointers to arrays
Assigning global pointers to local variables
You can't have global pointers to multi-dimensional VLAs where the variable lengths are not in the first dimension.
You should minimize the use of globals.
A more elegant version might go like this:
typedef struct point_ { int x; int y; } point;
point * create_array(size_t n)
{
return calloc(n, sizeof(point));
}
void free_array(point * p)
{
free(p);
}
int main()
{
size_t len = read_number_from_file();
point * data = create_array(len);
if (!data) { panic_and_die(); }
for (size_t i = 0; i != len; ++i)
{
/* manipulate data[i].x and data[i].y */
}
free_array(data);
data = 0; /* some people like to do this */
}
You are trying to assign an array but in C arrays cannot be assigned.
Use memcpy to copy one array to another array. Arrays elements in C are guaranteed to be contiguous.
int bla[N][M] = {0};
int blop[N][M];
/* Copy bla array to blop */
memcpy(blop, bla, sizeof blop);

Resources