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. */
Related
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};
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.
Using what I have learned here: How to use realloc in a function in C, I wrote this program.
int data_length; // Keeps track of length of the dynamic array.
int n; // Keeps track of the number of elements in dynamic array.
void add(int x, int data[], int** test)
{
n++;
if (n > data_length)
{
data_length++;
*test = realloc(*test, data_length * sizeof (int));
}
data[n-1] = x;
}
int main(void)
{
int *data = malloc(2 * sizeof *data);
data_length = 2; // Set the initial values.
n = 0;
add(0,data,&data);
add(1,data,&data);
add(2,data,&data);
return 0;
}
The goal of the program is to have a dynamic array data that I can keep adding values to. When I try to add a value to data, if it is full, the length of the array is increased by using realloc.
Question
This program compiles and does not crash when run. However, printing out data[0],data[1],data[2] gives 0,1,0. The number 2 was not added to the array.
Is this due to my wrong use of realloc?
Additional Info
This program will be used later on with a varying number of "add" and possibly a "remove" function. Also, I know realloc should be checked to see if it failed (is NULL) but that has been left out here for simplicity.
I am still learning and experimenting with C. Thanks for your patience.
Your problem is in your utilisation of data, because it points on the old array's address. Then, when your call realloc, this area is freed. So you are trying to access to an invalid address on the next instruction: this leads to an undefined behavior.
Also you don't need to use this data pointer. test is sufficient.
(*test)[n-1] = x;
You don't need to pass data twice to add.
You could code
void add(int x, int** ptr)
{
n++;
int *data = *ptr;
if (n > data_length) {
data_length++;
*ptr = data = realloc(oldata, data_length * sizeof (int));
if (!data)
perror("realloc failed), exit(EXIT_FAILURE);
}
data [n-1] = x;
}
but that is very inefficient, you should call realloc only once in a while. You could for instance have
data_length = 3*data_length/2 + 5;
*ptr = data = realloc(oldata, data_length * sizeof (int));
Let's take a look at the POSIX realloc specification.
The description says:
If the new size of the memory object would require movement of the object, the space for the previous instantiation of the object is freed.
The return value (emphasis added) mentions:
Upon successful completion with a size not equal to 0, realloc() returns a pointer to the (possibly moved) allocated space.
You can check to see if the pointer changes.
int *old;
old = *test;
*test = realloc(*test, data_length * sizeof(int));
if (*test != old)
printf("Pointer changed from %p to %p\n", old, *test);
This possible change can interact badly because your code refers to the "same" memory by two different names, data and *test. If *test changes, data still points to the old chunk of memory.
If this is a beginner's question, my apologies - most of my programming has been in very high level langauges, and I have limited expertise in C. (This is the sort of thing I could do very easily in languages such as Matlab, Octave, Sage, Maxima etc, but for this I need the speed of C).
But anyway... I have an array whose size is set at run time with malloc:
int *A = malloc(m * sizeof(int));
where m is computed from some values provided by the user. I have a function "update" which updates the array (or, if you prefer, takes the array as input and returns another as output). This update function may be called upwards of 10^8 times.
So the function itself can't introduce the appropriately sized output array with malloc, or the memory will be used up. So, for example, I can't do this:
int * update(int *L) /* produces next iteration of L */
{
int *out = malloc(m * sizeof(int));
/* do some stuff with L and produce new array out */
return (out);
}
I've tried to make out a static variable outside the update function:
static int *out;
and define its size in main:
out = malloc(m * sizeof(int));
But this doesn't seem to work either.
Anyway, I would be very grateful of some advice - I think I've exhausted the excellence of google.
Allocate the array outside of update, then pass a pointer to it:
void update(int const *L, int *out)
{
// whatever
}
Call as
int *A = malloc(m * sizeof(int));
if (A == NULL)
// handle error
for (i=0; i < N_ITER; i++)
update(L, A);
Though you may want to redesign the program so that it updates L in-place.
So if you are simply wanting to work on the data that is coming into the function directly, then what you have is partially already correct. The only thing that I would do is to add the size of the array as an input parameter to the routine to look like this:
void update(int * L, unsigned int size){
unsigned int count;
// Make sure the array has actually been allocated from outside
if(L == NULL) return;
// Example work on L just as if it is an array of values
for(count = 0; count < size; count++){
L[count] = L[count] + 1;
}
}
REMEMBER, this will work if you DO NOT wish to maintain the original data within L. If you do wish to maintain the original data, then larsmans answer will work better for you.
Also remember that you will have to malloc whatever variable you wish to input into L, outside and prior to your update routine, and free at some other point.
int * myVar = (int *)malloc(m * sizeof(int));
update(myVar, m);
// Other work to be done
free(myVar);
You should use realloc.
int *a = realloc(a, m * sizeof(a[0]));
It will work just as malloc in the first run but then it will reallocate a different sized array. You should note that the new array might or might not have the previous values assigned in it. You should assume that it has garbage like all things given by malloc.
Here is a good explanation of using realloc.
http://www.java-samples.com/showtutorial.php?tutorialid=589
NOTE : sizeof(a[0]) is equal to sizeof int but if you change int it will still be right
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);