Casting generic pointers in c - c

I found this code in a book, trying to explain how generic pointers works using this to copy one matrix to another one.
#include <stdio.h>
#define FILAS 2
#define COLS 3
void copiarMatrices(void *, void *, int);
int main(){
int m1[FILAS][COLS] = {24, 30, 15, 45, 34, 7};
int m2[FILAS][COLS];
copiarMatrices(m2, m1, sizeof(m1));
for (int i = 0; i < FILAS; i++){
for (int j = 0; j < COLS; j++) printf("%d ", m2[i][j]);
printf("\n");
}
}
void copiarMatrices(void *dest, void *orig, int n){
char *destino = (char *)dest;
char *origen = (char *)orig;
for (int i = 0; i < n; i++) {
destino[i] = origen[i];
}
}
The book said that the only data type that we could cast the void pointers was char because other data types are not allowed because of the bytes size.
I don't understand this and also if I execute the program with either int or double data type on void pointers the program get stuck for a few seconds and then finish well.

What the book is saying is that the result of the "sizeof" operator is the expression argument's size in bytes. If instead you were to specify "sizeof(m1) / sizeof(int)" then instead of "char *" you would need to cast the parameters to "int *" because you would then be passing the number of ints to copy instead of the number of bytes.

Function copiarMatrices copies buffer of any size. Let's imagine that buffer orig is 5 bytes. If you cast to int * inside copiarMatrices and int is 4 bytes and I want to copy all 5 bytes from orig to dest than n will not be integer (if n=1 than 4 bytes will be copied, if n=2 than 8 bytes will be copied but I need to copy 5 bytes). So, we can agree that copying will be by bytes and n means number of bytes which will be copied. In general you have to call copiarMatrices(m2, m1, FILAS * COLS * sizeof(int));

You do not need any special functions. You function copiarMatrices can be reduced to memcpy(m2, m1, sizeof(m1));
Some remarks.
Do not use int for sizes. Use the correct size_t type instead.
Try to be const correct.
Return a reference to the destination object, It will allow the function to be used in the expressions.
Your function prototype should be: void *copiarMatrices(void *, const void *, const size_t);. If you want to make the compiler life easier you may: void *copiarMatrices(void restrict *, const void * restrict, const size_t);

Related

Is it possible to use format specifiers as arguments for a function

I'm trying to write a function that allows me to initialise every element of a matrix with a given value. I'd like for this function to be as generic as possible, meaning that it would be able to treat matrices of any data type (float, char, etc).
The function would obviously need as one of the argument the value that the user wants the elements of the matrix to be initialised with. Since this value could be of any kind of data type, I don't know how to go about this.
Standard functions such as printf and scanf are able to accept arguments of any kind thanks to their use of format specifiers (%d, %f, etc). This got me wondering: how and is it even possible to use format specifiers in a programmer-defined function?
Ideally, my function would look something like this:
void initMatrix(void*** matrixToInit, int nRows, int nCols, const char format, void(?) value)
So that upon calling it I would have to write something like:
char matrixOfAs[3][3];
initMatrix(&matrixOfAs, 3, 3, "%c", 'A');
Is something like this feasible? Are there other solutions to this problem?
Assuming the matrix is a proper 2-D array of the element type (an array of array of element type), and not a 1-D array of pointer to element type, you could pass a void * pointer to the first element of the matrix to be initialized, the dimensions of the matrix, the element size, and a pointer to an initial element value as illustrated by the following:
#include <string.h>
#include <stdio.h>
void initMatrix(void *matrixToInit, unsigned int nRows, unsigned int nCols,
size_t elemSize, const void *elemVal)
{
size_t offset, end;
end = nRows * nCols * elemSize;
for (offset = 0; offset < end; offset += elemSize) {
memcpy((char *)matrixToInit + offset, elemVal, elemSize);
}
}
int main(void)
{
char matrixOfAs[3][3];
int i, j;
initMatrix(&matrixOfAs[0][0], 3, 3, sizeof(char), (char []){ 'A' });
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
printf(" %c", matrixOfAs[i][j]);
}
printf("\n");
}
return 0;
}
If you do not like the compound literal array value (char []){ 'A' } which I passed to the parameter elemVal (allowing the array value to decay to a pointer to its first element), you can replace it with a pointer to an initialized variable of type char in this case, e.g. define char a = 'A'; and replace (char []){ 'A' } with &a.
To make this function generic for any data type you choose to use, just create the function that doesnt handle a spesific data type but uses function pointers instead.
It means instead of passing this function the symbol of which type the user choose and then create a case for int, case for char and case for float, pass functions that hanle each type as an argument.
For example, make the function initMatrix like:
void initMatrix(void*** matrix, int nRows, int nCols, void(*creatematrix)(void ***, int, int));
Now, Create another function that handle the creation of int **matrix, lets call it void CreateIntMatrix(void ***matrix, int m, int m); and pass a pointer to this function as an argument of initmatrix function.
Now, when you call initMatrix to handle int data types, just call it like that:
void initMatrix(&matrixOfAs, 3, 3, CreateIntMatrix);
you should create as well function that handle char, double etc..
Now, when you creating the initMatrix function, create it like that:
void initMatrix(void*** matrix, int nRows, int nCols, void(*creatematrix)(void ***, int, int)){
/*Make something*/
creatematrix(matrix, nRows, nCols)//initialize any type of matrix
/*Make something*/
}

Why can't int (*p)[] be used as an argument for C function?

#include <stdio.h>
void print(int (*p)[3]);
int main(void)
{
int a[3] = {1, 2, 3};
print(&a);
return 0;
}
void print(int (*p)[3])
{
for (int i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
I have written a C function. See above.
It can print all the elements in an array.
There is one thing which is not so perfect : The number of array elements seems to be known in advance.
So I made some modification in hopes of making the function universal :
#include <stdio.h>
void print(int (*p)[]);
int main(void)
{
int a[3] = {1, 2, 3};
print(&a);
return 0;
}
void print(int (*p)[])
{
for (int i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
In the function, p is pointer pointing to the entire array.
However, it fails to be compiled.
Why can't int (*p)[] be used as an argument for C function?
int (*p)[] can be used as an argument for the function. The part of your code that gives the error is sizeof *p which is obviously not possible, because the type of *p is int[] which is an incomplete type and hence has no known size.
For the function to know the length of the array, you must design a way for the function to receive this information. Options include:
what you did in the original code.
passing the length as another argument.
including the length as an array element.
having a sentinel value on the end of the array.
The most common idiom would be to pass int *p, size_t n, you do not really gain anything by using pointer-to-array without the dimension being given.
The problem is that int [] is an incomplete type as the array has no defined size and therefore its sizeof cannot be taken.
In "modern C" (i.e. for almost 2 decades) you could have used variable-length arrays for this - you can pass the size as an argument and then the array:
#include <stdio.h>
#include <stdlib.h>
void print(size_t n, int (*p)[*]);
int main(void) {
int a[3] = {1, 2, 3};
print(3, &a);
}
void print(size_t n, int (*p)[n]) {
for (size_t i = 0; i < sizeof(*p) / sizeof(**p); i++)
printf("%d\n", (*p)[i]);
}
Of course this gains you nothing, since sizeof *p / sizeof **pp will be ... n. Therefore we might as well have used
void print(size_t n, int p[n]) {
for (size_t i = 0; i < p; i++)
printf("%d\n", p[i]);
}
which is less typing.
Short answer: int (*p)[] can't be used as an argument and have the function magically know the array size, because the standard says so.
Longer answer:
int (*p)[] is a pointer to an array, but the array has no defined size. So by looking at the array, it is impossible to do pointer arithmetic, calculate size of the thing p is pointing at, etc..
You don't have array of arrays so you don't need int (*p)[]. You have an array of int, so int *p or int p[] should be enough. This does not solve the problem of knowing the size of your array in print. To do this you basically have 3 options
Hardcode the value in the function
Put a sentinel value in your array to mark the end
Pass the size as a separate parameter like this:
void print(int n, int p[n])
Just remember that whatever method you use, parameter passing of arrays will always use pointers behind the scenes, so you CAN NOT use sizeof(p) to calculate the size of the array. sizeof will always return the size of a pointer in those situations

C program to increment each element of an array passed

C novice here.
I am trying to write a program containing function that takes in an array pointer, and each element of the array passed in the main function is incremented by 1. This is what I have tried:
#include <stdio.h>
#include <stdint.h>
void array_incr(int8_t *, uint8_t);
int main (void){
int8_t *arr[] = {0xAB, 0xCB, 0xC4, 0x84};
array_incr(arr, sizeof(arr)/sizeof(arr[0]);
int i;
for (i = 0; i < 4; i++)
printf("%d", arr[i]);
}
void array_incr(int8_t *arr, uint8_t len){
int i;
for(i=0; i<len; i++)
arr[i]++;
}
This is compiling with a lot of warnings and errors. Could someone please tell me where I am going wrong, while maintaining the same format of implementation?
Multiple problems indeed:
Incorrect type in declaration int8_t *arr[] = {0xAB, 0xCB, 0xC4, 0x84};: you should remove the * as arr is an array of numbers, not an array of pointers. Furthermore, the values are larger than 127 which is the maximum value for type int8_t, you should use uint8_t or a larger type.
Missing ) at the end of array_incr(arr, sizeof(arr)/sizeof(arr[0]);
There is no \n in the printf("%d", arr[i]); output statement. The values will come out in a single sequence of digits (and negative signs, since the values are actually negative for type int8_t).
Here is a corrected version:
#include <stdio.h>
#include <stdint.h>
void array_incr(uint8_t *, uint8_t);
int main(void) {
uint8_t arr[] = { 0xAB, 0xCB, 0xC4, 0x84 };
array_incr(arr, sizeof(arr) / sizeof(arr[0]));
int i;
for (i = 0; i < 4; i++)
printf("%d\n", arr[i]);
}
void array_incr(uint8_t *arr, uint8_t len) {
int i;
for (i = 0; i < len; i++)
arr[i]++;
}
First of all, it would be best to include said list of warnings and errors, but with such a small program it's mostly alright.
Into the matter, you declared your array wrong ; it should be int8_t arr[] (you included an extra *). You want an array of integers, not a pointer to an array of integers nor an array of pointers to integers (you can't initialise the former like that anyway).
sizeof doesn't work like you think it does. It returns the number of bytes taken up by the variable or type in memory. For example, on most modern system sizeof(int) returns 4, as would something like int a = 1; sizeof(a), and just like sizeof(arr) in your case. arr is not an array, it's a pointer to an array, so it's technically an int (thus 4 bytes). You would have to create an additional variable and manually hold the array's size if it were to change.
EDIT : tried it, seems to work. I remember that it doesn't but apparently it does ...

C pointer "type ** name" versus "type * name[]" as argument

I had a bit of a confusion. Below is a very simple example which works:
#include <stdlib.h>
typedef struct
{
unsigned char one: 1;
unsigned char two:1;
unsigned char three: 1;
unsigned char four: 1;
} nibble_bits;
typedef union
{
unsigned char all : 4;
nibble_bits bits;
} nibble;
void initArr(nibble ** arrLoc, unsigned int size)
{
nibble * start = arrLoc[0];
int i =0;
for (i=0; i<size; i++)
{
start[i].all = 0;
}
}
int main()
{
nibble * fourNibbles = (nibble *) malloc(4 * sizeof(nibble));
initArr(&fourNibbles,4);
}
This compiles fine with no warnings. However, when I change the first line in main:
nibble * fourNibbles = (nibble *) malloc(4 * sizeof(nibble));
to:
nibble fourNibbles[4];
I get the following:
warning: main.c: In function ‘main’:
main.c:150: warning: passing argument 1 of ‘initArr’ from incompatible pointer type
Upon running, I get a "Bus error 10".
Seems to me like the lines are doing the same thing, except that the malloc is allocating space for the array on the heap and the array declaration is on the stack. But (I thought) either way "fourNibbles" is of type "pointer to nibble", and hence the address of "fourNibbles" would be pointer to pointer to nibble (nibble **).
What am I missing here?
These are not even remotely the same. This
nibble * fourNibbles = (nibble *) malloc(4 * sizeof(nibble));
declares a pointer fourNibbles, while this
nibble fourNibbles[4];
declares an array. Arrays and pointers are two completely different things, which (at object level) have nothing in common. Trying to use them interchangeably in object contexts (like & operator) will only lead to disaster. There lots of information on this topic here on SO (search for "array pointer difference") as well as in this [de-facto standard] C FAQ: http://c-faq.com/aryptr/index.html
There is another thing that draws attention in your code though. Your function
void initArr(nibble ** arrLoc, unsigned int size)
is specifically tailored to the first variant, since it requires a pointer to a pointer as its first argument. It will not work if you attempt to force a pointer to an array to the first argument (which you already had a chance to observe firsthand).
However, the real question here is why your initArr function is written in such a bizarre way. This sequence
void initArr(nibble ** arrLoc, unsigned int size)
{
...
nibble * start = arrLoc[0];
...
start[i].all = 0;
looks rather unusual. Why are you passing a pointer to a pointer instead of an ordinary single-level pointer? E.g. you could simply do
void initArr(nibble *start, unsigned size)
{
unsigned i;
for (i = 0; i < size; ++i)
start[i].all = 0;
}
This version would be called as
initArr(fourNibbles,4); /* note: no `&` operator */
and it would be compatible with both malloc-ed arrays and explicitly declared arrays.
P.S. In C language a better idiom for malloc is
nibble * fourNibbles = malloc(4 * sizeof *fourNibbles);
Note that in this variant type name nibble is mentioned only once.
You are missing that the address of an array has a different type from the pointer that the plain array name becomes when used in an expression.
That is:
int *a1 = ...;
int a2[] = { ... };
some_func(&a1);
some_func(&a2);
cannot be correct unless some_func() expects a void *. The first call passes an int ** — a pointer to pointer to int; the second call passes an int (*)[] — a pointer to array of int. Drop the & from the array.
However, in your code, the problems are more complex. Because the function expects a nibble **, you have problems. What you should be doing is passing a nibble *:
void initArr(nibble *arrLoc, unsigned int size)
{
for (unsigned int i = 0; i < size; i++)
start[i].all = 0;
}
int main(void)
{
nibble *fourNibbles_1 = (nibble *) malloc(4 * sizeof(nibble));
nibble fourNibbles_2[4];
initArr(fourNibbles_1, 4);
initArr(fourNubbles_2, 4);
initArr(&fourNubbles_2[0], 4);
}
Your actual code is doing some really rather weird stuff. How much damage it is doing may depend on how big a pointer is compared to a nibble.

How do I write functions which accept two-dimensional arrays when the width is not known at compile time?

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.

Resources