Array of pointers - memory allocation - c

I'm new into array of pointers (putting functions into array) and allocating memory for it using malloc. Can you help me with this piece of code? Have functions: int comp_int(int a, int b); int comp_int_abs(int a, int b); int comp_int_length(int a, int b); int comp_int_digits_sum(int a, int b);
and would like to put pointers to these functions in array of pointers. Firstly would like to dynamically allocate memory for the array and put functions' pointers into it. Stuck in this place, what am I doing wrong?
int (**funcs)(int, int) = malloc(4*sizeof(int));
if(!*funcs)
{
printf("Failed to allocate memory");
return 8;
}
*funcs={add_int, sub_int, div_int, mul_int};

First off, why allocate dynamic memory?
If you use a normal array, things get a bit simpler:
int (*funcs[])(int, int) = {
comp_int,
comp_int_abs,
comp_int_length,
comp_int_digits_sum,
};
If you want to use dynamic allocation, there are a few things to look out for.
int (**funcs)(int, int) = malloc(4 * sizeof *funcs);
First we need to allocate the right amount of memory. By multiplying with the size of the dereferenced pointer, we don't have to worry about the element type of the dynamic array. (But if we wanted to write the type manually, it would be sizeof (int (*)(int, int)), not sizeof (int) as in your code; the elements of our array are pointers to functions, not integers.)
Then we check for allocation failure:
if (!funcs) {
Note: We check the pointer itself (funcs), not the first element of the dynamic array (which may not exist!) as in your code (*funcs). If malloc fails and returns NULL, then !*funcs will try to dereference a null pointer, which will most likely crash your program.
fprintf(stderr, "Failed to allocate memory\n");
Error messages go to stderr, not stdout. Lines are terminated by '\n'.
return 8;
}
Since we don't have a real array here, we can't use initialization syntax. In particular, = { is not valid in assignment expressions.
The most straightforward solution is to assign the elements manually:
funcs[0] = comp_int;
funcs[1] = comp_int_abs;
funcs[2] = comp_int_length;
funcs[3] = comp_int_digits_sum;
It's a bit error prone because we have to specify every index manually. However, we can combine this with the "normal array" code from above:
int (*const funcs_init[])(int, int) = {
comp_int,
comp_int_abs,
comp_int_length,
comp_int_digits_sum,
};
int (**funcs)(int, int) = malloc(sizeof funcs_init);
if (!funcs) { ... }
memcpy(funcs, funcs_init, sizeof funcs_init);
We just initialize our array as usual (here called funcs_init), then copy the contents into our dynamically allocated memory using memcpy.

First, change the allocation from:
int (**funcs)(int, int)=malloc(4*sizeof(int));
to
int (**funcs)(int, int)=malloc(4*sizeof(*funcs));
Change
*funcs={add_int, sub_int, div_int, mul_int};
to
funcs[0]=add_int;
funcs[1]=sub_int;
funcs[2]=div_int;
funcs[3]=mul_int;
The notation with braces, {} can only be used upon initializations and not assignments. If you use an array instead of a pointer, you can do this:
int (*funcs[4])(int, int)={add_int, sub_int, div_int, mul_int};

Related

How to pass an array with unknown 1-d dimension into function in C

I try something like below but all the time I have a segmentation fault.
I don't really want to use (e.g.) #define N 1000 and then declare int buffer[N].
Just in case..I'm not allowed to use any headers except stdio.h as well as dynamic memory.
void input (int *buffer, int *length);
int main()
{
int length, *buffer = NULL, *numbers = NULL;
input(buffer, &length);
}
void input(int *buffer, int *length) {
scanf("%d", length);
if (*length < 0) {
error = 1;
return;
}
for (int i = 0; i < *length; i++) {
scanf("%d", *buffer[i]);
}
}
How to pass an array with unknown 1-d dimension into function
In C, arrays cannot exist until their size is known.
There are other approaches though.
In C, code cannot pass an array to a function. some_function(some_array) converts the array some_array to the address of the first element of the array: &some_array[0]. That is what the function receives, a pointer, not an array. The original size information of the array is not passed, thus also pass the length to the function.
Sample:
Read desired length.
{
int length = 0;
scanf("%d", &length);
Form a variable length array, length >= 1.
if (length <= 0) {
return NULL;
}
int buffer[length];
Now call a function, passing the length and the address of the first element of the array.
// Do stuff with length and buf, like read data
foo1(length, buffer);
// foo1() receives the length & address of the first element of the array as an int *
// Do more stuff with length and buf, like write data
foo2(length, buffer);
}
At the end of the block }, buffer no longer available.
In C, you can't create an array if you can't know its size at compile time (or at least not in certain implementations and standards), so doing something like buffer[length] won't work (again at least not in certain implementations/standards).
What you need to do to make sure this works everywhere is to use a pointer (as I see you're trying to use here). However, what you're doing wrong here that causes your segfault with the pointers is you assign them the value of NULL. This also won't work due to how when you assign a pointer an arbitrary value, there is no memory allocated for the pointer (This applies for everything other than addresses of "regular" variables using the & operator and assigning other pointers that are checked to be OK). Your pointers are just pointing to address 0 and can't be used for anything.
What you need to do here to fix the pointers is to use dynamic memory allocation, so you can have a truly variable-sized array. Specifically, you need to use a function like malloc or calloc to allocate memory for the pointers so they are usable. In your case, using calloc and reading its documentation, we see that it takes 2 parameters: The number of elements it should allocate memory for and the size of each element. We also know that it returns a pointer to the starting address of the allocated memory and that in case of failure (which can only happen if you're out of memory), it returns NULL. Using this, we understand that in your case the call to calloc would be like this:
int *buffer = (int *) calloc(length, sizeof(int));
The sizeof() function returns the size of a data type in bytes. Here you allocated enough memory for the pointer to hold length integers (since you'll use it as an array you need enough memory for all the integers, you're not just pointing to 1 integer but storing all of them), and calloc is also noted to initialize every allocated element to 0, so you have an array of integers that are all initialized to 0 (Also note that type casting has been used to make sure the allocated memory block is appropriate for use with an integer array, you can read more about type casting in this small article from Tutorialspoint if you'd like). Then, after this has been allocated, you can start reading your integers into the array. The complete code looks like this:
void input (int *buffer, int *length);
int main() {
// NOTE: I don't see the numbers pointer used here, maybe remove it?
int length, *buffer, *numbers;
input(buffer, &length);
}
void input(int *buffer, int *length) {
scanf("%d", length);
if (*length < 0) {
// Consider printing the exact error here
error = 1;
return;
}
buffer = (int *) calloc(length, sizeof(int));
if (buffer == NULL) {
printf("Couldn't allocate memory for buffer\n");
error = 1;
return;
}
// Accessing the elements of an array doesn't need * and in fact * here can (and probably will) cause terrible things
for (int i = 0; i < *length; i++) {
scanf("%d", buffer[i]);
}
}
Also don't forget to call free() on the pointer after you're done using it to avoid memory leaks (in your case that'd be after the call to input()).
Hope this helped, good luck!
You cannot use arrays because their memory size must be known to the compiler at compile time. Also you can't use Variable Length Arrays because they are allocated at the point of declaration and deallocated when the block scope containing the declaration exits.
The solution to your problem might be to use malloc

How to dynamically allocate an array of integers in C

A portion of my C code is shown below.
int data[10]={1,3,6,8,1,7,9,1,1,1};
b=10;
int out[b];
process(data, &b, out);
alpha (out, b);
data and out are int arrays. The function process takes the array data whose length is pointed by b (=10) and performs mathematical operation and then returns an array out whose length is then again returned by b (unknown and hence required to be dynamically allocated). Then the array out is sent with function alpha. Right now the function alpha always sends out[10] since b has been declared as 10 in second line of code. How can I allocate array out dynamically so that it contains only valid data returned after function process.
You need to know the difference between dynamic and static allocations.
There are 3 alternatives:
Static allocation:
You need to know in advance the array length. It must be a number and not a variable:
int out[10];
Array is static and is only locally scoped. So if you do:
function do_something()
{
int out[10];
}
you can't use the out array outside the function. But you can define out
outside and send it like this:
function do_something(int* out)
{
// do things
}
...
{
int out[10];
do_something(out);
}
Automatic allocation
When you do
int b = 100;
int out[b];
(which won't compile on gcc without the -std=c99 or -std=c11 flag), you get an automatic variable, which is very convenient if you don't use out out of scope, but can be a bit dangerous. The resulting array is generated in the Stack, and is destroyed when it goes out of scope (which is why it can get you into trouble if you use it freely). See
https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Variable-Length.html
We suggest you use:
Dynamic allocation
Where the array is generated on the Heap and you are responsible to clean it up when you're done with it. The down side is you need to clean it up yourself. The up side is you can use pass it around and use it anywhere.
int b=100;
int* out = (int*) malloc(b * sizeof(int));
// do things with out
free(out);
VERY IMPORTANT:
Do not change the value of the pointer out. If you do, then you won't free the right amount of memory. A nice thing to do is to copy the pointer, and use the copied address for free:
int b=100;
int* out = (int*) malloc(b * sizeof(int));
int* out_copy = out;
// do things with out. don't touch out_copy
free(out_copy);
int *out;
out=(int *) malloc(sizeof(int) * 10);
This will produce array out of integer type with size 10.
You need out to be a pointer - not an array - and you need to pass a pointer to out to the function, just like you do with b.
Example:
void f(int **a, int *size)
{
*a = malloc(23 * sizeof(**a));
*size = 23;
}
/* ... */
int *p = NULL;
int b = 0;
f(&p, &b);
/* 'p' has been allocated and 'b' has its size. */

How to return a char** in C

I've been trying for a while now and I can not seem to get this working:
char** fetch (char *lat, char*lon){
char emps[10][50];
//char** array = emps;
int cnt = -1;
while (row = mysql_fetch_row(result))
{
char emp_det[3][20];
char temp_emp[50] = "";
for (int i = 0; i < 4; i++){
strcpy(emp_det[i], row[i]);
}
if ( (strncmp(emp_det[1], lat, 7) == 0) && (strncmp(emp_det[2], lon, 8) == 0) ) {
cnt++;
for (int i = 0; i < 4; i++){
strcat(temp_emp, emp_det[i]);
if(i < 3) {
strcat(temp_emp, " ");
}
}
strcpy(emps[cnt], temp_emp);
}
}
}
mysql_free_result(result);
mysql_close(connection);
return array;
Yes, I know array = emps is commented out, but without it commented, it tells me that the pointer types are incompatible. This, in case I forgot to mention, is in a char** type function and I want it to return emps[10][50] or the next best thing. How can I go about doing that? Thank you!
An array expression of type T [N][M] does not decay to T ** - it decays to type T (*)[M] (pointer to M-element array).
Secondly, you're trying to return the address of an array that's local to the function; once the function exits, the emps array no longer exists, and any pointer to it becomes invalid.
You'd probably be better off passing the target array as a parameter to the function and have the function write to it, rather than creating a new array within the function and returning it. You could dynamically allocate the array, but then you're doing a memory management dance, and the best way to avoid problems with memory management is to avoid doing memory management.
So your function definition would look like
void fetch( char *lat, char *lon, char emps[][50], size_t rows ) { ... }
and your function call would look like
char my_emps[10][50];
...
fetch( &lat, &lon, my_emps, 10 );
What you're attempting won't work, even if you attempt to cast, because you'll be returning the address of a local variable. When the function returns, that variable goes out of scope and the memory it was using is no longer valid. Attempting to dereference that address will result in undefined behavior.
What you need is to use dynamic memory allocation to create the data structure you want to return:
char **emps;
emps = malloc(10 * sizeof(char *));
for (int i=0; i<10; i++) {
emps[i] = malloc(50);
}
....
return emps;
The calling function will need to free the memory created by this function. It also needs to know how many allocations were done so it knows how many times to call free.
If you found a way to cast char emps[10][50]; into a char * or char **
you wouldn't be able to properly map the data (dimensions, etc). multi-dimensional char arrays are not char **. They're just contiguous memory with index calculation. Better fit to a char * BTW
but the biggest problem would be that emps would go out of scope, and the auto memory would be reallocated to some other variable, destroying the data.
There's a way to do it, though, if your dimensions are really fixed:
You can create a function that takes a char[10][50] as an in/out parameter (you cannot return an array, not allowed by the compiler, you could return a struct containing an array, but that wouldn't be efficient)
Example:
void myfunc(char emp[10][50])
{
emp[4][5] = 'a'; // update emp in the function
}
int main()
{
char x[10][50];
myfunc(x);
// ...
}
The main program is responsible of the memory of x which is passed as modifiable to myfunc routine: it is safe and fast (no memory copy)
Good practice: define a type like this typedef char matrix10_50[10][50]; it makes declarations more logical.
The main drawback here is that dimensions are fixed. If you want to use myfunc for another dimension set, you have to copy/paste it or use macros to define both (like a poor man's template).
EDITa fine comment suggests that some compilers support variable array size.
So you could pass dimensions alongside your unconstrained array:
void myfunc(int rows, int cols, char emp[rows][cols])
Tested, works with gcc 4.9 (probably on earlier versions too) only on C code, not C++ and not in .cpp files containing plain C (but still beats cumbersome malloc/free calls)
In order to understand why you can't do that, you need to understand how matrices work in C.
A matrix, let's say your char emps[10][50] is a continuous block of storage capable of storing 10*50=500 chars (imagine an array of 500 elements). When you access emps[i][j], it accesses the element at index 50*i + j in that "array" (pick a piece of paper and a pen to understand why). The problem is that the 50 in that formula is the number of columns in the matrix, which is known at the compile time from the data type itself. When you have a char** the compiler has no way of knowing how to access a random element in the matrix.
A way of building the matrix such that it is a char** is to create an array of pointers to char and then allocate each of those pointers:
char **emps = malloc(10 * sizeof(char*)); // create an array of 10 pointers to char
for (int i = 0; i < 10; i++)
emps[i] = malloc(50 * sizeof(char)); // create 10 arrays of 50 chars each
The point is, you can't convert a matrix to a double pointer in a similar way you convert an array to a pointer.
Another problem: Returning a 2D matrix as 'char**' is only meaningful if the matrix is implemented using an array of pointers, each pointer pointing to an array of characters. As explained previously, a 2D matrix in C is just a flat array of characters. The most you can return is a pointer to the [0][0] entry, a 'char*'. There's a mismatch in the number of indirections.

How to differentiate empty and 0 in an int array in C?

I'm a beginner of C and now I'm learning pointer and dynamic memory allocation. I want to write a simple program to create empty arrays and check for the existence of a given number. Here's my code:
/* create an empty array pointer */
int* createArray(){
int *a = (int*) malloc(sizeof(int));
return a;
}
void findArrayElement(int *list, int element){
int i;
int len = (sizeof(list) / sizeof(int));
if (sizeof(list) == 0) {
printf("NO\n");
return;
}
for (i=0; i<len; i++) {
if (list[i] == element) {
printf("YES\n");
return;
}
}
printf("NO\n");
}
int main(int argc, const char * argv[]) {
int *p;
p = createArray();
printf("size of int is: %lu\n", sizeof(int));
printf("size of p is: %lu\n", sizeof(p));
printf("LENGTH of p is: %lu\n", ARRLENGTH(p));
findArrayElement(p, 2);
findArrayElement(p, 0);
return 0;
}
But when I run the program, I always get 'YES' when I looking for 0, so
Is there a way to differentiate integer 0 and a complete empty array?
Also I'm not sure whether my function createArray() is a correct way to create an empty array.
Thanks guys.
Is there a way to differentiate integer 0 and a complete empty array?
How do you define an empty array? Once you allocate a memory chunk and assign it to a pointer, it already has some value (which is undefined in case of alloc). The most used way to mark a pointer as not used or not allocated os to assign NULL to it.
Also I'm not sure whether my function createArray() is a correct way to create an empty array.
sizeof returns the number of bytes which the given object (or type) occupies in the memory. In your case sizeof(list) returns 8 as it is a pointer.
In oder to allocate an array, the function has to receive its size. Currently it always allocates size for one integer only.
Edit: Adding example.
/* create an empty array pointer */
int* createArray(size_t size)
{
return (size ? (int*) malloc(sizeof(int)*size) : NULL);
}
So now the returned pointer should be 'coupled' with the size of the array. Which means that each function that receives an array as a parameter should receive also its size.
sizeof returns the memory size of the array pointer, regardless of contents.
edit: if it exists in memory, it will be nonzero.
edit 3: removed inaccurate information, see the comments about creating a variable to record the length. Also from comments, note that your createArray function is creating an array for exactly 1 integer. In C, arrays are of fixed length. So this Array will always be the same size (whether you stored something in it or not). sizeof(pointer) will always return the memory allocated for the pointer, not the memory allocated for the array at which it is pointing.

C Pointer help: Array/pointer equivalence

In this toy code example:
int MAX = 5;
void fillArray(int** someArray, int* blah) {
int i;
for (i=0; i<MAX; i++)
(*someArray)[i] = blah[i]; // segfault happens here
}
int main() {
int someArray[MAX];
int blah[] = {1, 2, 3, 4, 5};
fillArray(&someArray, blah);
return 0;
}
... I want to fill the array someArray, and have the changes persist outside the function.
This is part of a very large homework assignment, and this question addresses the issue without allowing me to copy the solution. I am given a function signature that accepts an int** as a parameter, and I'm supposed to code the logic to fill that array. I was under the impression that dereferencing &someArray within the fillArray() function would give me the required array (a pointer to the first element), and that using bracketed array element access on that array would give me the necessary position that needs to be assigned. However, I cannot figure out why I'm getting a segfault.
Many thanks!
I want to fill the array someArray, and have the changes persist outside the function.
Just pass the array to the function as it decays to a pointer to the first element:
void fillArray(int* someArray, int* blah) {
int i;
for (i=0; i<MAX; i++)
someArray[i] = blah[i];
}
and invoked:
fillArray(someArray, blah);
The changes to the elements will be visible outside of the function.
If the actual code was to allocate an array within fillArray() then an int** would be required:
void fillArray(int** someArray, int* blah) {
int i;
*someArray = malloc(sizeof(int) * MAX);
if (*someArray)
{
for (i=0; i<MAX; i++) /* or memcpy() instead of loop */
(*someArray)[i] = blah[i];
}
}
and invoked:
int* someArray = NULL;
fillArray(&someArray, blah);
free(someArray);
When you create an array, such as int myArray[10][20], a guaranteed contiguous block of memory is allocated from the stack, and normal array arithmetic is used to find any given element in the array.
If you want to allocate that 3D "array" from the heap, you use malloc() and get some memory back. That memory is "dumb". It's just a chunk of memory, which should be thought of as a vector. None of the navigational logic attendant with an array comes with that, which means you must find another way to navigate your desired 3D array.
Since your call to malloc() returns a pointer, the first variable you need is a pointer to hold the vector of int* s you're going to need to hold some actual integer data IE:
int *pArray;
...but this still isn't the storage you want to store integers. What you have is an array of pointers, currently pointing to nothing. To get storage for your data, you need to call malloc() 10 times, with each malloc() allocating space for 20 integers on each call, whose return pointers will be stored in the *pArray vector of pointers. This means that
int *pArray
needs to be changed to
int **pArray
to correctly indicate that it is a pointer to the base of a vector of pointers.
The first dereferencing, *pArray[i], lands you somewhere in an array of int pointers, and the 2nd dereferencing, *p[i][j], lands you somewhere inside an array of ints, pointed to by an int pointer in pArray[i].
IE: you have a cloud of integer vectors scattered all over the heap, pointed to by an array of pointers keeping track of their locations. Not at all similar to Array[10][20] allocated statically from the stack, which is all contiguous storage, and doesn't have a single pointer in it anywhere.
As others have eluded to, the pointer-based heap method doesn't seem to have a lot going for it at first glance, but turns out to be massively superior.
1st, and foremost, you can free() or realloc() to resize heap memory whenever you want, and it doesn't go out of scope when the function returns. More importantly, experienced C coders arrange their functions to operate on vectors where possible, where 1 level of indirection is removed in the function call. Finally, for large arrays, relative to available memory, and especially on large, shared machines, the large chunks of contiguous memory are often not available, and are not friendly to other programs that need memory to operate. Code with large static arrays, allocated on the stack, are maintenance nightmares.
Here you can see that the table is just a shell collecting vector pointers returned from vector operations, where everything interesting happens at the vector level, or element level. In this particular case, the vector code in VecRand() is calloc()ing it's own storage and returning calloc()'s return pointer to TblRand(), but TblRand has the flexibility to allocate VecRand()'s storage as well, just by replacing the NULL argument to VecRand() with a call to calloc()
/*-------------------------------------------------------------------------------------*/
dbl **TblRand(dbl **TblPtr, int rows, int cols)
{
int i=0;
if ( NULL == TblPtr ){
if (NULL == (TblPtr=(dbl **)calloc(rows, sizeof(dbl*))))
printf("\nCalloc for pointer array in TblRand failed");
}
for (; i!=rows; i++){
TblPtr[i] = VecRand(NULL, cols);
}
return TblPtr;
}
/*-------------------------------------------------------------------------------------*/
dbl *VecRand(dbl *VecPtr, int cols)
{
if ( NULL == VecPtr ){
if (NULL == (VecPtr=(dbl *)calloc(cols, sizeof(dbl))))
printf("\nCalloc for random number vector in VecRand failed");
}
Randx = GenRand(VecPtr, cols, Randx);
return VecPtr;
}
/*--------------------------------------------------------------------------------------*/
static long GenRand(dbl *VecPtr, int cols, long RandSeed)
{
dbl r=0, Denom=2147483647.0;
while ( cols-- )
{
RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF;
r = sqrt(-2.0 * log((dbl)(RandSeed/Denom)));
RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF;
*VecPtr = r * sin(TWOPI * (dbl)(RandSeed/Denom));
VecPtr++;
}
return RandSeed;
}
There is no "array/pointer" equivalence, and arrays and pointers are very different. Never confuse them. someArray is an array. &someArray is a pointer to an array, and has type int (*)[MAX]. The function takes a pointer to a pointer, i.e. int **, which needs to point to a pointer variable somewhere in memory. There is no pointer variable anywhere in your code. What could it possibly point to?
An array value can implicitly degrade into a pointer rvalue for its first element in certain expressions. Something that requires an lvalue like taking the address (&) obviously does not work this way. Here are some differences between array types and pointer types:
Array types cannot be assigned or passed. Pointer types can
Pointer to array and pointer to pointer are different types
Array of arrays and array of pointers are different types
The sizeof of an array type is the length times the size of the component type; the sizeof of a pointer is just the size of a
pointer

Resources