value of pointer to a char array vs plain char pointer - c

I am having a hard time understanding where I can use a pointer to an array,
e.g: char (*a)[10];.
So two basic questions.
Please give me a simple example of how just a pointer to an array can be used in C code.
Why would one use it as apposed to just declaring a variable as a pointer and then incrementing/decrementing the address after that point.

Say you have a database query that returns a set of strings. Further, say that you know that these strings are no longer than 9 characters in length. Only, you don't know how many elements are in the set returned by the query.
char (*a)[10] = malloc( NumRecords * sizeof *a );
if ( a == NULL )
{
/* Handle error appropriately */
return EXIT_FAILURE; /* Naive */
}
for ( i = 0 ; i < NumRecords ; ++i )
{
assert(strlen(DbRecordSet[i]) < 10);
strcpy(a[i], DbRecordSet[i]);
}

Example: how to print the elements of an array of num_row rows and 3 columns:
#include <stdio.h>
#define NUM_ROW(x) (sizeof (x) / sizeof *(x))
// print elements of an array of num_row rows and 3 columns
void print(int (*a)[3], size_t num_row)
{
size_t num_col = sizeof *a / sizeof **a;
for (int i = 0; i < num_row; i++) {
for (int j = 0; j < num_col; j++) {
printf("%d\n", a[i][j]);
}
}
}
int main(void)
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
int b[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
print(a, NUM_ROW(a));
print(b, NUM_ROW(b));
return 0;
}

Any time you pass an expression with a multi-dimensioned array type to a function, you're going to be working with a pointer to an array:
int a[10][20];
foo(a);
void foo(int (*p)[20]) // or int p[][20]
{ ... }

Related

pointer to pointer as 2d array

My background is Java therefore I'm not used to pointers, the following code throws error and I can't see way:
#include <stdio.h>
#define DIM 2
void sort_intervals(int** intervals, int n);
int main()
{
int a[3][DIM] = {
{1, 6} ,
{4, 9} ,
{3,17} };
sort_intervals(a, 3);
return 0;
}
void sort_intervals(int** intervals, int n)
{
printf("%d ", intervals[0][0]);//<--- error here
}
Error: Access violation reading location
I'm not allowed to change the function signiture
Then you need an array of pointers that point to arrays.
int a_1[DIM] = {1, 6};
int a_2[DIM] = { ... };
int a_3[DIM] = { ... };
int *a[3] = { a_1, a_2, a_3, }; // array of 3 pointers
sort_intervals(a, 3);
or exactly equivalent using compound literals you can:
int *a[3] = { (int[DIM]){1, 6}, (int[DIM]){2, 7}, (int[DIM]){3, 17}};
sort_intervals(a, 3);
even:
sort_intervals((int*[3]){
(int[DIM]){1, 6},
(int[DIM]){2, 7},
(int[DIM]){3, 17},
}, 3);
I am assuming you can change main function.
You could also initialize a as double pointer such as:
int **a = (int**)calloc(3, sizeof(int*)); //setting a as array of 3 pointers
for (int i = 0; i < 3; i++)
*a = (int*) calloc(DIM, sizeof(int)); //assigning pointer to a[0], a[1] and a[2]
Here a is array of 3 integer pointers. a[0],a[1] and a[2] are int pointers.
You can modify a as a[0][0] = 5;
If you can't change the signature as you explained in your comment, then you can get it done using a jagged array:
#define DIM 2
void sort_intervals(int** intervals, int n);
int main()
{
int **a = malloc(3 * sizeof(int*));
for (int i = 0; i < 3; i++) {
a[i] = malloc(DIM * sizeof(int));
}
a[0][0] = 1; a[0][1] = 6;
a[1][0] = 4; a[1][1] = 9;
a[2][0] = 3; a[2][1] = 17;
sort_intervals(a, 3);
for (int i = 0; i < 3; i++) {
free(a[i]);
}
free(a);
return 0;
}
void sort_intervals(int** intervals, int n)
{
printf("%d ", intervals[2][0]);//<--- error here
}

Why can we not use dynamic arrays as parameters of functions that use static array parameters?

I'm studying the C language and data structures. I wish to get some detailed explanation about why we cannot use dynamic arrays as parameters of functions that use static array parameters.
#include <stdio.h>
int sumAry2D_f1(int ary[][3], int rows, int cols);
void freeAry2D(int **ary, int rows);
int main(void)
{
int ary2D[][3] = { {1, 2, 3}, {4, 5, 6} }; // static array
int r, c;
int **ary = (int**)malloc(sizeof(int*) * 2); // dynamic array
for (r = 0; r < 2; r++)
ary[r] = (int*)malloc(sizeof(int)*3);
for (r = 0; r < 2; r++)
for (c = 0; c < 3; c++)
ary[r][c] = r + c; // 0, 1, 2, 1, 2, 3
printf("sumAry2D_f1() %d\n", sumAry2D_f1(ary2D, 2, 3));
// why we can`t function like this?
// printf("sumAry2D_f1~3() %d\n", sumAry2D_f1(ary, 2, 3));
freeAry2D(ary, 2); // free function of dynamic array
return 0;
}
int sumAry2D_f1(int ary[][3], int rows, int cols)
{
int i, j, sum = 0;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
sum += ary[i][j];
return sum;
}
void freeAry2D(int **ary, int rows)
{
int i;
for (i = 0; i < rows; i++)
free(ary[i]);
free(ary);
}
// why we can`t function like this?
// printf("sumAry2D_f1~3() %d\n", sumAry2D_f1(ary, 2, 3));
Your function specifically expects a pointer to an integer pointer that points to a sequence of 3 integers, or an array of 3-element integer arrays, not just any pointer to integer pointer. ary is just a pointer to integer pointer. Although you made your int ** have the same structure as your int [][3], it could have been different and the compiler can't tell because the memory allocation occurs at run-time, hence if you uncomment the code it probably won't compile, and even if it does the behavior will be undefined.
Unfortunately, you would need 2 functions to do what you want:
int sumAry2D_f1(int ary[][3], int rows, int cols);
and
int sumAry2D_f12(int** ary, int rows, int cols);
The code inside each function would be the same.

Pointer to existing 2d array of unknown size?

I have the following:
struct matrix {
int h;
int w;
int** data;
};
int m1[2][2] = {
{1, 2},
{3, 4}
};
int m2[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
struct matrix matrix1 = {2, 2, m1};
struct matrix matrix2 = {3, 3, m2};
This gives the error 'initialisation from incompatible pointer type'. What pointer type should I be using?
You may be interested in the variable length arrays of C99. This solution does not directly answer your question about how to initialize the structure with a properly typed data (one can't); but you can use a simple pointer to store the array's address and then cast to the variable length array pointer when using struct matrix.
The user side would just call functions like printFroMat() which receive a single argument of type struct matrix; the code inside these functions (so to speak, the library implementation) would perform the somewhat unsightly casts, as demonstrated. The typedef makes the cast perhaps a little more understandable because it demonstrates where the variable name in a declaration would go.
Note that the funny sizeof(m2)/sizeof(*m2) etc. are not strictly necessary, you can just say 3. But the sizeof expression automatically stays in sync with the actual matrix size, which quickly becomes a real asset.
You can pass "arrays" (in fact: still just addresses, but of a known array type) together with their dimensions as parameters to functions, and index them the normal way (below in printMatrix). Example:
#include<stdio.h>
#include<string.h>
struct matrix {
int h;
int w;
int *data; // first element of matrix
};
int m2[4][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{10, 11, 12}
};
void printMatrix(int dim1, int dim2, int mat[][dim2] )
{
printf("Address of matrix: %p\n", (void *)mat);
for(int i1=0; i1<dim1; i1++)
{
for(int i2=0; i2<dim2; i2++)
{
printf("%d ", mat[i1][i2]);
}
putchar('\n');
}
}
void printFromMat(struct matrix mat)
{
printMatrix(mat.h, mat.w, (int (*)[mat.w])mat.data);
// or:
typedef int (*mT)[mat.w];
printMatrix(mat.h, mat.w, (mT)mat.data);
}
int main()
{
printMatrix( sizeof(m2) /sizeof(*m2), // number of highest-order elements
sizeof(*m2)/sizeof(**m2), // number of second-order elements per highest-order
m2 ); // address of the first sub-array
struct matrix mat = { sizeof(m2) /sizeof(*m2), sizeof(*m2)/sizeof(**m2), *m2 };
printFromMat(mat);
return 0;
}
Sample session:
$ gcc -std=c99 -Wall -o 2d-matrix 2d-matrix.c && ./2d-matrix
Address of matrix: 0x100402020
1 2 3
4 5 6
7 8 9
10 11 12
Address of matrix: 0x100402020
1 2 3
4 5 6
7 8 9
10 11 12
Address of matrix: 0x100402020
1 2 3
4 5 6
7 8 9
10 11 12
2d array is not a pointer to pointer.
How to use the void *.
#include <stdio.h>
struct matrix {
int h;
int w;
void *data;
};
int m1[2][2] = {
{1, 2},
{3, 4}
};
int m2[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
struct matrix matrix1 = {2, 2, m1};
struct matrix matrix2 = {3, 3, m2};
int main(void){
int i, j;
int (*matp)[matrix2.w] = matrix2.data;//Back from the void* to pointer to array
for (i=0; i<matrix2.h; i++){
for(j=0; j<matrix2.w; j++)
printf("%d ", matp[i][j]);
puts("");
}
printf("\n");
return 0;
}
A matrix, as you declared, is not a pointer to pointer. Use a simple pointer to point its element.
#include <stdio.h>
struct matrix {
int h;
int w;
int* data;
};
int m1[2][2] = {
{1, 2},
{3, 4}
};
int m2[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
struct matrix matrix1 = {2, 2, &m1[0][0]};
struct matrix matrix2 = {3, 3, &m2[0][0]};
int main(int argc, char **argv)
{
int i, j;
for (i=0; i<matrix2.h; i++)
for(j=0; j<matrix2.w; j++)
printf("%d ", matrix2.data[(i*matrix2.h)+j]);
printf("\n");
}
EDIT
To answer to the comment, you can use compound literal as below. In this way you could access it with [i][j]
#include <stdio.h>
struct matrix {
int h;
int w;
int** data;
};
int *m2[3] = {
(int[]){1, 2, 3},
(int[]){4, 5, 6},
(int[]){7, 8, 9}
};
struct matrix matrix2 = {3, 3, m2};
int main(int argc, char **argv)
{
int i, j;
for (i=0; i<matrix2.h; i++)
for(j=0; j<matrix2.w; j++)
printf("%d ", matrix2.data[i][j]);
printf("\n");
}
You may not initialize the structure such a way like
struct matrix matrix1 = {2, 2, m1};
struct matrix matrix2 = {3, 3, m2};
because there is no conversion from types int ( * )[2] and int ( * )[3] to type int **
I suggest to allocate memory for copies of the arrays dynamically.
The approach can look the following way as it is shown in the demonstrative program
#include <stdlib.h>
#include <stdio.h>
struct matrix
{
size_t h;
size_t w;
int **data;
};
int m1[2][2] =
{
{ 1, 2 },
{ 3, 4 }
};
int m2[3][3] =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
struct matrix init( size_t h, size_t w, int a[h][w] )
{
struct matrix matrix = { 0 };
matrix.data = malloc( h * sizeof( int * ) );
if ( matrix.data )
{
matrix.h = h;
matrix.w = w;
for ( size_t i = 0; i < h; i++ )
{
matrix.data[i] = malloc( w * sizeof( int ) );
if ( matrix.data[i] )
{
for ( size_t j = 0; j < w; j++ ) matrix.data[i][j] = a[i][j];
}
}
}
return matrix;
}
int main( void )
{
struct matrix matrix1 = init( 2, 2, m1 );
struct matrix matrix2 = init( 3, 3, m2 );
for ( size_t i = 0; i < matrix1.h; i++ )
{
for ( size_t j = 0; j < matrix1.w; j++ ) printf( "%d ", matrix1.data[i][j] );
printf( "\n" );
}
printf( "\n" );
for ( size_t i = 0; i < matrix2.h; i++ )
{
for ( size_t j = 0; j < matrix2.w; j++ ) printf( "%d ", matrix2.data[i][j] );
printf( "\n" );
}
printf( "\n" );
// free allocated arrays of matrix1 and matrix2
}
The program output is
1 2
3 4
1 2 3
4 5 6
7 8 9
You need also to write a function that will free the allocated memory for the structure.
The compiler must support variable length arrays.

Array of arrays, with different sizes

I'm having an array, that has arrays in every cell. For example, the big array is called arr:
int a[3] = {3, 2, 1};
int b[2] = {2, 1};
int *arr[2] = {a, b}
Now the problem is, if I want to print the small arrs, inside the big array.
Here is my code:
#include <stdio.h>
void printArr(int arr [], int n)
{
for (int i = 0 ; i < n ; i++)
{
printf("%d ", *(arr + i));
}
printf("\n");
}
int main()
{
int a[5] = {1, 8, 4, 2, 0};
int b[3] = {1, 4, 2};
int *arr [2] = {a, b};
int n = 0;
for (int i = 0 ; i < 2 ; i++)
{
printArr(*(arr + i), n);
}
}
The output is supposed to be something like this:
1 8 4 2 0
1 4 2
But I can't get the size of each array, since sizeof(*(arr + i) gives me 4, which is the size of the pointer (the name of the array), and not all the array it self.
So what can I do?
Thanks!
The Problem:
The C language only provides a way of finding the size of types.
This gives the subtle differences between applying sizeof to:
1) An array of a type such as:
int a[3];
sizeof(a); // => 3 * sizeof(int)
2) A pointer to the type:
int *ptr;
sizeof(ptr); // => sizeof(int *)
or
int a[3] = {3, 2, 1};
int b[2] = {2, 1};
int *arr[2] = {a, b};
sizeof(arr[1]); // => sizeof(int *)
Some solutions:
Store the size
As jfly proposes store the size of the arrays.
Makes finding the size a constant time operation.
Append an end marker
Adding a end marker like '\0' as used for c-style strings.
You might use INT_MAX or INT_MIN in this case.
The printArr implementation would need to change to:
void printArr(int *arr)
{
int *it = arr;
while(arr != INT_MIN);
{
printf("%d ", *it);
}
printf("\n");
}
Disadvantages:
Finding the size of the array requires iterating over the full array.
Gives the risk of an actual value colliding with the end marker value.
Advantages:
The varying sized array can be passed as a single argument.
Using iterators
Store the pointer to the first and one past the last value.
void printArr(int *begin, int *end)
{
for (int *it = begin; it != end; it++)
{
printf("%d ", *it);
}
printf("\n");
}
int *end_arr[2] = {a + 3, b + 2};
for (int i = 0 ; i < 2 ; i++)
{
printArr(arr[i], end_arr[i]);
}
Can be extended to other data structures.
Since arr is an array of pointers, so you can't get the size of array from the pointer which points to an array, you need additional size info:
int size_arr[2] = {sizeof(a) / sizeof(int), sizeof(b) / sizeof(int)};
for (int i = 0 ; i < 2 ; i++)
{
printArr(arr[i], size_arr[i]);
}

Insertion Sort Doing Nothing

I wrote the following insertion sort yesterday (I started learning C 3 days ago). For some reason, the sort does not modify the array AT ALL.
#include <stdio.h>
int *insert(int arr[], int index, int item);
int *isort(int arr[]);
int main() {
int a[17] = {1, 2, 9, 5, 3, 2, 1, 6, 5, 9, 0, 1, 3, 4, 2, 3, 4};
int *b = isort(a);
for (int i = 0; i < 17; i += 1) {
printf("%d ", b[i]);
}
return 0;
}
int *insert(int arr[], int index, int item) {
--index;
while (index >= 0 && item < arr[index]) {
arr[index + 1] = arr[index];
--index;
}
arr[index + 1] = item;
return arr;
}
int *isort(int arr[]) {
for (int i = 1; i < sizeof(arr) - 1; i++) {
arr = insert(arr, i, arr[i]);
}
return arr;
}
I'm thinking it could be my compiler, as I'm running a compiler that is on a non unix machine: lcc-win, but I'm not sure. Is there some fundamental thing I'm missing here?
int *isort(int arr[]) {
for (int i = 1; i < sizeof(arr) - 1; i++) {
arr = insert(arr, i, arr[i]);
}
return arr;
}
In this function sizeof(arr) actually returns the size of the pointer and not the size of the array.
In C a special rule says an array parameter is actually adjusted to a parameter of the corresponding pointer type.
That is:
int *isort(int arr[]) { /* ... */ }
is equivalent to this:
int *isort(int *arr) { /* ... */ }
To fix this, add a new parameter in your function that takes the size of the array:
int *isort(int arr[], size_t size) { /* ... */ }
The first problem, as has been pointed out, is that the isort function uses the sizeof operator on a pointer. The way C treats arrays is a little strange at first glance. The name of an array is a pointer to its first element. So when you call isort like this:
int *b = isort(a);
you are simply pushing a pointer to the array onto the stack. In the definition of isort,
int *isort(int arr[])
declares arr to be a pointer to int just like
int *isort(int *arr)
C is even more confusing in this respect: if you had said:
int *isort(int arr[17])
the arr variable is still just a pointer to int ... the "17" here is discarded! Even with this syntax, sizeof(arr) will still be the size of a pointer to int.
On a 32-bit system (ILP32), sizeof(arr) will always be 4, however big the array is.
Therefore, you need to pass the size of the array to isort. A good general way to do this is to define a macro like this:
#define NITEMS(arr) (sizeof(arr)/sizeof(arr[0]))
This will calculate the number of elements in an array of any type.
Your next problem is more a style one than an actual error:
arr = insert(arr, i, arr[i]);
This calls the insert function with a reference to "arr". The array is modified through this reference, and then a pointer to that array is returned. It will always be the same pointer as you sent in the first place, so this assignment actually does nothing, harmlessly. Like I say, a style problem, not a code error.
The final issue is your isort function stops one short (after you correct the sizeof problem), since you went from 1 to sizeof-1. Here is a fixed version:
#include <stdio.h>
#define NITEMS(arr) (sizeof(arr)/sizeof(arr[0]))
int *insert(int arr[], int index, int item);
int *isort(int arr[], size_t nitems);
int main() {
int a[17] = {1, 2, 9, 5, 3, 2, 1, 6, 5, 9, 0, 1, 3, 4, 2, 3, 4};
int *b = isort(a, NITEMS(a));
for (int i = 0; i < NITEMS(a); i += 1) {
printf("%d ", b[i]);
}
printf("\n");
return 0;
}
int *insert(int arr[], int index, int item) {
--index;
while (index >= 0 && item < arr[index]) {
arr[index + 1] = arr[index];
--index;
}
arr[index + 1] = item;
return arr;
}
int *isort(int arr[], size_t nitems) {
for (int i = 1; i < nitems; i++) {
insert(arr, i, arr[i]);
}
return arr;
}

Resources