Lets say you had an array like this
{ 1 2 5 7 2 3 7 4 2 1 }
And you wanted to store that the difference between the first half of the array and the second half is at positions 2 and 4.
The trick is, I need to use those stored numbers later in other code, so what I can't figure out is how I would store these numbers.
I have this method
int * getPositions(int *array, int size){
int * c[(size/2)];
int counter = 0;
for(int i = 0; i < size /2; i++) {
if (*(array + i) != *(array + (size - 1) - i)) {
c[counter]= (int *) i;
counter++;
}
}return (int *) c;
}
but it seems to be storing -1774298560 into every location. I know that cause when I try to print it
int c = (int) getPositions(array, size_of_array);
for(int i = 0; i < ((size_of_array/2)); i++){
printf("%d\t", c);
}
all it prints out is
-1774298560 -1774298560 -1774298560 -1774298560 -1774298560
PS: I have array and size_of_array initialized somewhere else.
PS: I have taken the comments into consideration and changed the code to the following
int * getPositions(int *array, int size){
int * c = (int *) malloc((size_t) (size/2));
int counter = 0;
for(int i = 0; i < size /2; i++) {
if (*(array + i) != *(array + (size - 1) - i)) {
c[counter]= i;
counter++;
}
}
If the function should return a simple int array, you need to declare a pointer-to-int, and then call malloc to reserve space for the array. Then fill in the array, and return the pointer. The calling function will need to free the memory at some point.
int *getPositions(int *array, int size)
{
int *c = malloc( (size/2) * sizeof(int) );
if ( c == NULL )
return NULL;
// put stuff in the array using array syntax, e.g.
c[0] = array[0];
return c;
}
Call the function like this
int *c = getPositions( array, size );
if ( c != NULL )
for( int i = 0; i < (size/2)); i++ )
printf( "%d\t", c[i] );
free( c );
Notes:
Yes, error checking in C is a pain, but you must do it, or your
program will randomly crash.
You are allowed to use array syntax with a pointer, just be sure you don't read or write past the end of the memory that the pointer references.
It's legal to pass a NULL pointer to free.
Another option.
int * getPositions(int *array, int size);
int main() {
int array[] = { 1, 2, 5, 7, 2, 3, 7, 4, 2, 1 };
int size_of_array = sizeof(array) / sizeof(int);
int *ptr = getPositions(array, size_of_array);
for(int i = 0; ptr[i] != '\0' ; i++){
printf("%d\t", *(ptr + i));
}
return 0;
}
int * getPositions(int *array, int size) {
int temp[size/2];
int counter = 0;
for (int i = 0; i < size / 2 ; i++) {
if (array[i] != array[(size - 1) - i]) {
temp[counter++] = i;
}
}
int *c = malloc(counter * sizeof(int));
for (int i = 0; i < counter; i++) {
c[i] = temp[i];
}
return c;
}
My compiler going mad actually...which compiler you're using? Any modern static analyzer should have warned you
aftnix#dev:~⟫ gcc -std=c11 -Wall st.c
st.c: In function ‘getPositions’:
st.c:8:25: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
c[counter]= (int *) i;
^
st.c:11:6: warning: function returns address of local variable [-Wreturn-local-addr]
}return (int *) c;
^
st.c: In function ‘main’:
st.c:16:13: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
int c = (int) getPositions(array, 10);
So compiler is showing all the problems of the code. And your edited code doesn't even compile :
aftnix#dev:~⟫ gcc -std=c11 -Wall st.c
st.c:4:4: error: expected identifier or ‘(’ before ‘[’ token
int[] getPositions(int *array, int size){
^
st.c: In function ‘main’:
st.c:17:5: warning: implicit declaration of function ‘getPositions’ [-Wimplicit-function-declaration]
int c = (int) getPositions(array, 10);
Couple of things you have to take into consideration.
If you need to return a storage address, never try to return a local variable. As local variables are allocated in the Stack. Stack frames have the same lifetime of the function. Use malloc and co to allocate memory at the Heap. Understanding how the Runtime data structures are allocated and used is a very essential for a C programmer as C doesn't have fancy magical stuff under the hood. C is pretty much bare metal.
Stack Vs Heap
When passing arrays/pointers around, you should first think about your design first. Do you want to change your original array "in place"? or you want a different copy of "transformed" array. Usually you should try to avoid changing a memory "in place" as there might be other users to that. But if don't have such worries, you can then design your function as a "input->output" basis. That means you will not be returning void, and will return the transformed array itself.
Related
I dynamically allocated memory for 3D array of pointers. My question is how many pointers do I have? I mean, do I have X·Y number of pointers pointing to an array of double or X·Y·Z pointers pointing to a double element or is there another variant?
double*** arr;
arr = (double***)calloc(X, sizeof(double));
for (int i = 0; i < X; ++i) {
*(arr + i) = (double**)calloc(Y, sizeof(double));
for (int k = 0; k < Y; ++k) {
*(*(arr+i) + k) = (double*)calloc(Z, sizeof(double));
}
}
The code you apparently intended to write would start:
double ***arr = calloc(X, sizeof *arr);
Notes:
Here we define one pointer, arr, and set it to point to memory provided by calloc.
Using sizeof (double) with this is wrong; arr is going to point to things of type double **, so we want the size of that. The sizeof operator accepts either types in parentheses or objects. So we can write sizeof *arr to mean “the size of a thing that arr will point to”. This always gets the right size for whatever arr points to; we never have to figure out the type.
There is no need to use calloc if we are going to assign values to all of the elements. We can use just double ***arr = malloc(X * sizeof *arr);.
In C, there is no need to cast the return value of calloc or malloc. Its type is void *, and the compiler will automatically convert that to whatever pointer type we assign it to. If the compiler complains, you are probably using a C++ compiler, not a C compiler, and the rules are different.
You should check the return value from calloc or malloc in case not enough memory was available. For brevity, I omit showing the code for that.
Then the code would continue:
for (ptrdiff_t i = 0; i < X; ++i)
{
arr[i] = calloc(Y, sizeof *arr[i]);
…
}
Notes:
Here we assign values to the X pointers that arr points to.
ptrdiff_t is defined in stddef.h. You should generally use it for array indices, unless there is a reason to use another type.
arr[i] is equivalent to *(arr + i) but is generally easier for humans to read and think about.
As before sizeof *arr[i] automatically gives us the right size for the pointer we are setting, arr[i].
Finally, the … in there is:
for (ptrdiff_t k = 0; k < Y; ++k)
arr[i][k] = calloc(Z, sizeof *arr[i][k]);
Notes:
Here we assign values to the Y pointers that arr[i] points to, and this loop is inside the loop on i that executes X times, so this code assigns XY pointers in total.
So the answer to your question is we have 1 + X + XY pointers.
Nobody producing good commercial code uses this. Using pointers-to-pointers-to-pointers is bad for the hardware (meaning inefficient in performance) because the processor generally cannot predict where a pointer points to until it fetches it. Accessing some member of your array, arr[i][j][k], requires loading three pointers from memory.
In most C implementations, you can simply allocate a three-dimensional array:
double (*arr)[Y][Z] = calloc(X, sizeof *arr);
With this, when you access arr[i][j][k], the compiler will calculate the address (as, in effect, arr + (i*Y + j)*Z + k). Although that involves several multiplications and additions, they are fairly simple for modern processors and are likely as fast or faster than fetching pointers from memory and they leave the processor’s load-store unit free to fetch the actual array data. Also, when you are using the same i and/or j repeatedly, the compiler likely generates code that keeps i*Y and/or (i*Y + j)*Z around for multiple uses without recalculating them.
Well, short answer is: it is not known.
As a classic example, keep in mind the main() prototype
int main( int argc, char** argv);
argc keeps the number of pointers. Without it we do not know how many they are. The system builds the array argv, gently updates argc with the value and then launches the program.
Back to your array
double*** arr;
All you know is that
arr is a pointer.
*arr is double**, also a pointer
**arr is double*, also a pointer
***arr is a double.
What you will get in code depends on how you build this. A common way if you need an array of arrays and things like that is to mimic the system and use a few unsigned and wrap them all with the pointers into a struct like
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
A CSV file for example is char ** **, a sheet workbook is char ** ** ** and it is a bit scary, but works. For each ** a counter is needed, as said above about main()
A C example
The code below uses arr, declared as double***, to
store a pointer to a pointer to a pointer to a double
prints the value using the 3 pointers
then uses arr again to build a cube of X*Y*Z doubles, using a bit of math to set values to 9XY9.Z9
the program uses 2, 3 and 4 for a total of 24 values
lists the full array
list the first and the very last element, arr[0][0][0] and arr[X-1][Y-1][Z-1]
frees the whole thing in reverse order
The code
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
int print_array(double***, int, int, int);
int main(void)
{
double sample = 20.21;
double* pDouble = &sample;
double** ppDouble = &pDouble;
double*** arr = &ppDouble;
printf("***arr is %.2ff\n", ***arr);
printf("original double is %.2ff\n", sample);
printf("*pDouble is %.2ff\n", *pDouble);
printf("**ppDouble is %.2ff\n", **ppDouble);
// but we can build a cube of XxYxZ doubles for arr
int X = 2;
int Y = 3;
int Z = 4; // 24 elements
arr = (double***)malloc(X * sizeof(double**));
// now each arr[i] must point to an array of double**
for (int i = 0; i < X; i += 1)
{
arr[i] = (double**)malloc(Y * sizeof(double*));
for (int j = 0; j < Y; j += 1)
{
arr[i][j] = (double*)malloc(Z * sizeof(double));
for (int k = 0; k < Z; k += 1)
{
arr[i][j][k] = (100. * i) + (10. * j) + (.1 * k) + 9009.09;
}
}
}
print_array(arr, X, Y, Z);
printf("\n\
Test: first element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n\
last element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n",
0, 0, 0, arr[0][0][0],
(X-1), (Y-1), (Z-1), arr[X-1][Y-1][Z-1]
);
// now to free this monster
for (int x = 0; x < X; x += 1)
{
for (int y = 0; y < Y; y += 1)
{
free(arr[x][y]); // the Z rows
}
free(arr[x]); // the plane Y
}
free(arr); // the initial pointer;
return 0;
}; // main()
int print_array(double*** block, int I, int J, int K)
{
for (int a = 0; a < I; a += 1)
{
printf("\nPlane %d\n\n", a);
for (int b = 0; b < J; b += 1)
{
for (int c = 0; c < K; c += 1)
{
printf("%6.2f ", block[a][b][c]);
}
printf("\n");
}
}
return 0;
}; // print_array()
The output
***arr is 20.21f
original double is 20.21f
*pDouble is 20.21f
**ppDouble is 20.21f
Plane 0
9009.09 9009.19 9009.29 9009.39
9019.09 9019.19 9019.29 9019.39
9029.09 9029.19 9029.29 9029.39
Plane 1
9109.09 9109.19 9109.29 9109.39
9119.09 9119.19 9119.29 9119.39
9129.09 9129.19 9129.29 9129.39
Test: first element is arr[0][0[0] = 9009.09 (9XY9.Z9)
last element is arr[1][2[3] = 9129.39 (9XY9.Z9)
I wrote the following function in C:
int last(long arr[], int length) {
for (int i = 0; i < length-1; i++)
if (*(arr+i) == *(arr + length - 1))
return 1;
return 0;
}
it checks if the last value of the array was used more than once. In the main:
int *arr = malloc(length*sizeof(int));
for (int i = 0; i < length; i++)
scanf("%d", ++arr);
printf(last((long *) arr, length);
For some reason for the array [1,2,2,3] it returns that the last element was used multiple times and I'm not sure why. I think that is because of scanf("%d", ++arr); but I don't know how to fix it.
My goal is that it will return 1 for [1,3,2,3] and 0 for [1,2,2,3]. What could be the problem?
You should use scanf("%d", &arr[i]);. Using ++arr causes the array to be incremented before you pass it to last, and also reads into data beyond arr, which is undefined behavior.
Another one of the issues in this is the cast to long *.
You should use %ld in scanf and long *arr = malloc(length*sizeof(*arr));.
Also make sure to check for NULL. You never know when malloc is going to fail or someone's going to pass bad data.
Full example:
#include <stdio.h>
#include <stdlib.h>
int last(long arr[], int length) {
if(!arr) return -1;
for (int i = 0; i < length-1; i++)
{
if (arr[i] == arr[length-1])
return 1;
}
return 0;
}
int main(void)
{
long *arr = malloc(4*sizeof(*arr));
if(!arr) return 1;
for (int i = 0; i < 4; i++)
scanf("%ld", &arr[i]);
printf("%d\n", last(arr, 4));
}
Several problems in your code:
Look at this statement:
scanf("%d", ++arr);
^^^^^
In the last iteration of loop, the pointer arr will be pointing to one element past end of array arr (due to pre-increment) and it is is passed to scanf(). The scanf() will access the memory location pointed by the pointer which is an invalid memory because your program does not own it. This is undefined behavior. Note that a pointer may point to one element past the end of array, this is as per standard but dereferencing such pointer will lead to undefined behavior.
Once the main() function for loop finishes the arr pointer pointing to location past the end of memory allocated to arr and just after this you are passing arr to last() function. So, you are passing an invalid memory reference to last() function and then accessing that memory in last() function - one more undefined behavior in your program.
Probably you should take another pointer and point it to arr, so that arr keep pointing to allcoated memory reference returned by malloc().
Note that if you want to read the input the way you are doing then use the post-increment operator in scanf(), like this:
int *arr = malloc(length*sizeof(int));
if (arr == NULL)
exit(EXIT_FAILURE);
int *ptr = arr;
for (int i = 0; i < length; i++)
scanf("%d", ptr++);
but the more appropriate and readable way is - scanf("%d", &arr[i]).
Another big problem in your code is accessing the int values as long type.
The last() function parameter arr type is long and you are passing it int pointer typecasted to long *.
Note that the size of long and int may be different based on the platform. You cannot assume them to be of same size on all platforms.
Assume the case where int size is 4 bytes and long size is 8 bytes.
In this case, when accessing an int pointer using long type pointer then every object will be considered as 8 byte long and when you do arr+1 in last(), the pointer will be advance by 8 bytes and you will never get correct result.
Compiler must be throwing warning message on this statement:
printf(last((long *) arr, length);
because the printf() expects first argument as const char * and you are passing it int (return type of last()). You should give the first argument to printf() a string which contains appropriate format specifier('s).
Putting these altogether:
#include <stdio.h>
#include <stdlib.h>
int last(int arr[], int length) {
if (arr == NULL) {
return 1;
}
for (int i = 0; i < length - 1; i++) {
if (arr[i] == arr[length - 1]) {
return 1;
}
}
return 0;
}
int main(void) {
int length = 4;
int *arr = malloc (length * sizeof (*arr));
if (arr == NULL) {
exit(EXIT_FAILURE);
}
printf ("Enter %d numbers:\n", length);
for (int i = 0; i < length; i++) {
scanf ("%d", &arr[i]);
}
printf ("Duplicate found: %s\n", last (arr, length) == 1 ? "Yes" : "No");
return 0;
}
Disclaimer: This is homework. I am attempting it and do not expect or want anyone to do it for me. Just a few pointers (hehe) where I'm going wrong would be appreciated.
The homework requires me to create an int* array that holds 10 elements, and then attempt to insert a million ints into it. Each insertion checks if the array needs to be resized, and if it does, I increase it's size so it can hold one more element.
When I insert 10,000 elements, it works fine, but if I try 100,000 elements, I get the following error:
*** glibc detected *** ./set2: realloc(): invalid old size: 0x00000000024dc010 ***
This is the code I'm running. I've commented it so it's easily readable.
void main()
{
//begin with a size of 10
int currentsize = 10;
int* arr = malloc(currentsize * sizeof(int));
int i;
//initalize with all elements set to INT_MAX
for(i = 0; i < currentsize; i++) {
arr[i] = INT_MAX;
}
// insert random elements
for(i = 0; i < 100000; i++) {
currentsize = add(rand() % 100,arr,currentsize);
}
free(arr);
}
/*
Method resizes array if needed, and returns the new size of the array
Also inserts the element into the array
*/
int add(int x, int* arr, int size)
{
//find the first available location
int newSize = size;
int i;
for(i = 0; i < size; i++) {
if (arr[i] == INT_MAX)
break;
}
if (i >= size) {
//need to realloc
newSize++;
arr = realloc(arr, newSize * sizeof(int) );
}
arr[i] = x;
return newSize;
}
The error is probably because you properly use realloc to change arr in the function add, but this modified value is lost when add returns. So the next call to add will receive the old, now bad value.
Also I can't understand why you're using a the for loop to search. You know you want to add at the last element, so why search? Just reallocate the array and plug the new value in the new slot.
Incidentally I'm pretty sure your teacher is trying to get you to see that reallocating for each member causes an asymptotic run time problem. Most implementations of realloc will do a lot of copying with this algorithm. This is why real programs grow the array size by a factor greater than one (often 1.5 or 2) rather than by fixed amounts.
The usual idiom is to abstract the variable size array in a struct:
typedef struct array_s {
int *elts;
int size;
} VARIABLE_ARRAY;
void init(VARIABLE_ARRAY *a)
{
a->size = 10;
a->elts = malloc(a->size * sizeof a->elts[0]);
// CHECK FOR NULL RETURN FROM malloc() HERE
}
void ensure_size(VARIABLE_ARRAY *a, size_t size)
{
if (a->size < size) {
// RESET size HERE TO INCREASE BY FACTOR OF OLD SIZE
// size = 2 * a->size;
a->elts = realloc(size * sizeof a->elts[0]);
a->size = size;
// CHECK FOR NULL RETURN FROM realloc() HERE
}
}
// Set the i'th position of array a. If there wasn't
// enough space, expand the array so there is.
void set(VARIABLE_ARRAY *a, int i, int val)
{
ensure_size(a, i + 1);
a->elts[i] = val;
}
void test(void)
{
VARIABLE_ARRAY a;
init(&a);
for (int i = 0; i < 100000; i++) {
set(&a, i, rand());
}
...
}
I would pass arr to add() as a pointer (to a pointer), so that it can be modified inside of add()
int add(int x, int** arr, int size)
{
// ...
*arr = realloc(*arr, newSize * sizeof(int) );
}
And calling it....
currentsize = add(rand() % 100, &arr, currentsize);
Note that that your code (and my suggested change) is not doing any error checking. You should be checking the return value of malloc and realloc for NULL.
I have coded a generic insertion sort in C, and it works really fine.
But, On my function of insertion sort, it gets a void** arr,
and on its signature it gets a void* arr, otherwise, it doesn't work.
Why is it so?
Do we have any other ways to code the insertion sort to be generic?
The Full code is here:
#include <stdio.h>
#include <malloc.h>
#define SIZE 10
int cmp(void* elm1, void* elm2);
void insertionSort(void* arr, int size);
int main()
{
int arr[] = {5, 8, 2, 3, 15, 7, 4, 9, 20, 13};
int arr2[] = {1};
int i;
for (i = 0; i < SIZE; i++)
printf("%d ", arr[i]);
printf("\n");
insertionSort(&arr, SIZE);
for (i = 0; i < SIZE; i++)
printf("%d ", arr[i]);
return 0;
}
void insertionSort(void** arr, int size)
{
int i = 1;
int j;
void* temp;
while (i < size)
{
if (cmp(arr[i], arr[i-1]) == -1)
{
temp = arr[i];
j = i - 1;
while (j >= 0 && cmp(arr[j], temp) == 1)
{
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = temp;
}
i++;
}
}
int cmp(void* elm1, void* elm2)
{
if ((int)elm1 == (int)elm2)
return 0;
else if ((int)elm1 > (int)elm2)
return 1;
else
return -1;
}
The code as it is, is undefined, because of multiple problems. It just happens to work, because on your system the size of the pointer is the same as the size of the type int.
You code will not compile without warnings (if you enable them). The function insertionSort and it's prototype must have the same type.
You should change the type in the function definition to
void insertionSort(void* arr, int size)
And then cast the pointer arr, to an appropriate type. Since this is a generic sort, like qsort(), the only realistic option is a cast to char*. This means you will also have to pass the size of the type into the function, so the pointer can be incremented correctly. This will require you to change the function drastically.
So, the function prototype should really be the same as qsort:
void Sort(void* arr, size_t size , size_t object_size , int(*)( const void* , const void* ))
The problem is that integers are not pointers, so your test array is of type *int or int[]. But in your function, you don't know that and you try to make your code work with pointers. So you expect * void[]. If you change your temp variable to int, you don't need the ** in the signature. The same way, if you want to keep the "generic" (as you call), you need an array of *int.
Basically, in C you cannot write a function working out of the box for both primary types and pointers. You need some tricks. Have a look at this stackoverflow, maybe it will help.
I create a 2-D array using malloc. When I use printf to print the array element in for loop, everything is fine. But when I want to use printf in main, these is a Segmentation fault: 11.
Could you please tell me what the problem with the following code is?
#include <stdlib.h>
#include <stdio.h>
void initCache(int **cache, int s, int E){
int i, j;
/* allocate memory to cache */
cache = (int **)malloc(s * sizeof(int *)); //set
for (i = 0; i < s; i++){
cache[i] = (int *)malloc(E * sizeof(int)); //int
for(j = 0; j < E; j++){
cache[i][j] = i + j;
printf("%d\n", cache[i][j]);
}
}
}
main()
{
int **c;
initCache (c, 2, 2);
printf("%d\n", c[1][1]); // <<<<<<<<<< here
}
Since your cache is a 2D array, it's int**. To set it in a function, pass int***, not int**. Otherwise, changes to cache made inside initCache have no effect on the value of c from main().
void initCache(int ***cache, int s, int E) {
int i, j;
/* allocate memory to cache */
*cache = (int **)malloc(s * sizeof(int *)); //set
for (i = 0; i < s; i++) {
(*cache)[i] = (int *)malloc(E * sizeof(int)); //int
for(j = 0; j < E; j++){
(*cache)[i][j] = i + j;
printf("%d\n", (*cache)[i][j]);
}
}
}
Now you can call it like this:
initCache (&c, 2, 2);
You changed a local variable, which won't effect the local variable c in main.
If you want to allocate in the function, why pass a variable? Return it from the function.
int **c = initCache(2, 2);
You could use a return, or else a *** as suggested by others. I'll describe the return method here.
initCache is creating and initializing a suitable array, but it is not returning it. cache is a local variable pointing to the data. There are two ways to make this information available to the calling function. Either return it, or pass in an int*** and use that to record the pointer value.
I suggest this:
int** initCache(int **cache, int s, int E){
....
return cache;
}
main()
{
int **c;
c = initCache (2, 2);
printf("%d\n", c[1][1]); <<<<<<<<<< here
}
====
Finally, it's very important to get in the habit of checking for errors. For example, malloc will return NULL if it has run out of memory. Also, you might accidentally as for a negative amount of memory (if s is negative). Therefore I would do:
cache = (int **)malloc(s * sizeof(int *));
assert(cache);
This will end the program if the malloc fails, and tell you what line has failed. Some people (including me!) would disapprove slightly of using assert like this. But we'd all agree it's better than having no error checking whatsoever!
You might need to #include <assert.h> to make this work.