Let's suppose I have this function:
void arrayExtendDouble(int **ptArr, int *size)
{
*ptArr = realloc(*ptArr, (*size * 2) * sizeof(int));
for(int i = (*size * 2) - 1; i >= *size; i--)
ptArr[i] = fib(i); //this will throw SEG FAULT
*size *= 2;
}
Note: I am a student and this is the valid resolution a teacher gave.
Now, the only way i can make this work is like this:
void fibArrayExpand(int **ptArr, int *size)
{
int *ptArrNew = realloc(*ptArr, (*size * 2) * sizeof(int));
for(int i = (*size * 2) - 1; i >= *size; i--)
ptArrNew[i] = fib(i);
*size *= 2;
*ptArr = ptArrN;
}
Supposedly the first one (teacher's) is correct and the second one (mine) it's not because i do extra steps not needed.
I would like to know why does it throw segmentation fault, is it supposed to do so or is the function well written?
The first snippet isn't correct. ptAtr isn't the pointer to the ints; it's a pointer to another pointer, *ptAtr, which is the pointer to the ints. As such,
ptArr[i] = fib(i);
should be
(*ptArr)[i] = fib(i);
Alternate explanation
It's pretty easy to see the following code achieves the correct result:
void arrayExtendDouble(int** arr_ptr, int* size_ptr)
{
// Copy values from caller.
int* arr = *arr_ptr;
int size = *size_ptr;
arr = realloc(arr, (size * 2) * sizeof(int));
for(int i = (size * 2) - 1; i >= size; i--)
arr[i] = fib(i);
size *= 2;
// Pass back modified values to caller.
*arr_ptr = arr;
*size_ptr = size;
}
You might notice that arr and *arr_ptr have the same value, and so do size and size_ptr. That means we could simply replace all instances of arr and size with *arr_ptr and *size_ptr respectively.
void arrayExtendDouble(int** arr_ptr, int* size_ptr)
{
*arr_ptr = realloc(*arr_ptr, (*size_ptr * 2) * sizeof(int));
for(int i = (*size_ptr * 2) - 1; i >= *size_ptr; i--)
(*arr_ptr)[i] = fib(i);
*size_ptr *= 2;
}
Note that (*arr_ptr)[i] = fib(i); is used instead of arr[i] = fib(i);. The first snippet you posted is therefore incorrect.
Related
I'm trying to code a resizable array, which expands when it's full. All functions are working, but the resize one isn't.
int main(void)
{
int arr[4];
int *ptr = arr;
initializeEmptyArray(ptr);
insertAtIndex(ptr, 0, 4);
insertAtIndex(ptr, 0, 3);
insertAtIndex(ptr, 0, 2);
insertAtIndex(ptr, 0, 1);
resizeArray(&ptr);
for (int i = 0; i < capacity; i++)
{
printf("%i", arr[i]);
}
}
This initiates my array [1,2,3,4] and then calls the resize array to test it.
void resizeArray(int **arr)
{
int *newArr = (int *)malloc(capacity * 2 * sizeof(int));
for (int i = 0; i < capacity; i++)
{
newArr[i] = (*arr)[i];
}
for (int i = capacity; i < capacity * 2; i++)
{
newArr[i] = EMPTY;
}
free(*arr);
*arr = newArr;
}
The problem is the value of arr when I print it doesn't change to [1,2,3,4,-1,-1,-1,-1] (-1 represents empty). How can I change the pointer to point to this new array?
Capacity stands for the number of elements the array support, initiated as 4
EMPTY is defined as -1, to represent a empty slot in the array.
The two main issues with the code is that arr is allocated on the stack in main(), and then you free() it in resizerArray(). That is a defect, and I fixed that my heap allocating arr in main() instead. In your loop, you print arr[i] but pass ptr to resizeArray() which is updated, but arr still points to memory that is now free'ed. I fixed this issue by eliminated the ptr variable:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define EMPTY 0
void resizeArray(int **arr, size_t capacity) {
int *newArr = malloc(2 * capacity * sizeof(int));
// for (int i = 0; i < 2 * capacity; i++) {
// newArr[i] = i < capacity ? (*arr)[i] : EMPTY;
// }
memcpy(newArr, *arr, capacity * sizeof(int));
memset(newArr + capacity, EMPTY, capacity * sizeof(int));
free(*arr);
*arr = newArr;
}
int main(void) {
size_t capacity = 4;
int *arr = malloc(capacity * sizeof(int));
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
for (int i = 0; i < capacity; i++) {
printf("before: %d\n", arr[i]);
}
resizeArray(&arr, capacity);
capacity *= 2;
for (int i = 0; i < capacity; i++) {
printf("after: %d\n", arr[i]);
}
}
I comment out the loop in resizeArray so you can see how you would do that. The code prints:
before: 1
before: 2
before: 3
before: 4
after: 1
after: 2
after: 3
after: 4
after: 0
after: 0
after: 0
after: 0
Both resizeArray() and the calling code has to know about the factor 2. This is not a great design. Maybe pass in old and new capacity? Or pass in size_t *capacity that can be updated if you want to hard-code the factor in resizeArray()? Remember to check the return value of malloc() to ensure it did not fail.
See realloc() for the standard way to resize heap allocated memory, and calloc() for how to get pre-initialized memory.
You can't resize an array. It's size is fixed.
So if you want something that can be resized do:
int arr[4]; --> int* arr = malloc(4 * sizeof *arr);
BTW:
It seems you miss a line like:
capacity = 2 * capacity ;
Hava a look at "realloc", your question sounds like a perfect match
You can not resize an array with automatic storage duration. You can do this with arrays that have allocated storage duration.
So you should remove the array declaration in main and write
int *ptr = malloc( 4 * sizeof( int ) );
or
int *ptr = malloc( capacity * sizeof( int ) );
Also you forgot to change the value of the variable capacity. I suppose that it is not declared as a constant variable.
In this case the function resizeArray can look for example the following way
int resizeArray( int **arr )
{
int *newArr = realloc( *arr, capacity * 2 * sizeof(int));
int success = newArr != NULL;
if ( success )
{
*arr = newArr;
for (int i = capacity; i < capacity * 2; i++)
{
newArr[i] = EMPTY;
}
capacity *= 2;
}
return success;
}
Pay attention to that a reallocation of the array can fail. So the function should signal to the caller whether the reallocation was successful.
Also it is not a good idea to use the variable capacity as a global variable.
You could write in main
int capacity = 4;
int *ptr = malloc( capacity * sizeof( int ) );
// ...
and call the function like
resizeArray( &ptr, &capacity );
In this case the function will look the following way
int resizeArray( int **arr, int *capacity )
{
int *newArr = realloc( *arr, *capacity * 2 * sizeof(int));
int success = newArr != NULL;
if ( success )
{
*arr = newArr;
for (int i = *capacity; i < *capacity * 2; i++)
{
newArr[i] = EMPTY;
}
*capacity *= 2;
}
return success;
}
I have the task to write a program in C. The program should be able to check for parameters and create arrays that are as big as the parameter I gave. I have to fill the array with random numbers. Works fine so far. Later on my task is to sort the array using pointers. First thing is I did not quite understand how pointers work but I made the sorting work so far. The only problem is, that I can only sort to a size of 4. If my parameter is bigger than 4 I get the first 4 numbers sorted and then a Segmentation fault. I cannot find the issue but the fun part is, that if I add a printf just to print my parameter again it works fine for any parameter I want! I do not know what is happening!
Here is the exact task again, because I think I didn't describe it that well:
To do this, create a dynamic pointer field of the same size and initialize it with pointers to the elements of the int field. When sorting, the pointers should now be sorted so that the first pointer points to the smallest int value, the second to the next largest value, and so on.
int main(int argc, char *argv[]) {
int *array;
int **arrpointer;
int size = atoi(argv[1]);
if (size == 0) {
fprintf(stderr, "Wrong parameter!\n");
return EXIT_FAILURE;
}
//printf("Array-Size : "); //First I had it with scanf, which works perfectly fine without a print
//scanf("%d", &size);
printf("Input%d", size); //This is the print I need somehow!
// allocate memory
array = (int *)malloc(size * sizeof(int)); // Init Array
arrpointer = (int **)malloc(size * sizeof(int)); // Init Pointer Array
//Check Pointer array
if (arrpointer != NULL) {
printf("Memory allocated\n\n");
} else {
fprintf(stderr, "\nNo free memory.\n");
return EXIT_FAILURE;
}
if (array != NULL) {
printf("Memory is allocated\n\n");
//Fill Array
for (int i = 0; i < size; i++) {
array[i] = rand() % 1000; //I know it is not random right now, will add later
int *temp = &array[i];
arrpointer[i] = temp; //Pointer fill
}
} else {
fprintf(stderr, "\nNo free memory to allocate.\n");
return EXIT_FAILURE;
}
shakersort(arrpointer, size); //Function to sort pointers
zeigeFeld(arrpointer, size); //Function to Print
free(array);
free(arrpointer);
return EXIT_SUCCESS;
}
I know its a bit confusing, I am sorry.
I will also add the code where I sort it below.
void swap(int **a, int **b) {
int ram;
ram = **a;
**a = **b;
**b = ram;
}
void shakersort(int **a, int n) {
int p, i;
for (p = 1; p <= n / 2; p++) {
for (i = p - 1; i < n - p; i++)
if (*a[i] > *a[i+1]) {
swap(&a[i], &a[i + 1]);
}
for (i = n - p - 1; i >= p; i--)
if (*a[i] < *a[i-1]) {
swap(&a[i], &a[i - 1]);
}
}
}
This is the code I tried to build for the pointers and it works fine so far.
I hope someone can help or give some input to why my print fixes the problem. I really dont understand!
Thank you for your time and help, let me know if I should add anything!
The program has undefined behavior because the allocation size is incorrect for the array:
arrpointer = (int **)malloc(size * sizeof(int));
allocates space for size integers, but it should allocate space for size pointers to int, which on 64-bit systems are larger than int. Use this instead:
arrpointer = (int **)malloc(size * sizeof(int *));
Or use the type of the destination pointer:
arrpointer = malloc(sizeof(*arrpointer) * size);
This latter syntax is much safer as it works for any non void pointer type.
Note however that this array of pointers is overkill for your purpose. You should just implement the sorting functions on arrays of int:
void swap(int *a, int *b) {
int ram = *a;
*a = *b;
*b = ram;
}
void shakersort(int *a, int n) {
int p, i;
for (p = 1; p <= n / 2; p++) {
for (i = p - 1; i < n - p; i++) {
if (a[i] > a[i + 1]) {
swap(&a[i], &a[i + 1]);
}
}
for (i = n - p - 1; i >= p; i--) {
if (a[i] < a[i - 1]) {
swap(&a[i], &a[i - 1]);
}
}
}
}
Whether the above code actually sorts the array is unclear to me, I never use shakersort.
why do you use pointers before printf??
first you need to know what the pointer is:
the pointer is some kind of variable that contains address of some another variable.
for example:
int b = 2;
int * a = &b;
a variable include the address of variable b. then if you print ((a)) it will give you hex number which is the address of b. if you print ((*a)), compiler will print what in the address that int the variable a and print the amount of number in address of cell b(that means 2).
now i guess you understand what the pointer is, look again at your code and correct the mistakes.
I updated my code from
arrpointer = (int **) malloc(size * sizeof(int));
to
arrpointer = malloc(sizeof *arrpointer * size);
And it works fine!
Thank you all for your help!
Allocations :
cell **initBoard(int boardSize)
{
int i, j, k;
cell **matrix;
matrix = (cell **) malloc((boardSize + 1) * sizeof(cell *));
// init upper frame
matrix[0] = (cell *) malloc((boardSize + 1) * sizeof(cell));
matrix[0][0].type = (char *) malloc(3 * sizeof(char));
matrix[0][0].type[0] = ' ';
for (k = 1; k <= boardSize; k++)
{
// +1 for null char ?
matrix[0][k].type = (char *) malloc(3 * sizeof(char));
matrix[0][k].type = arrNo[k - 1];
}
// init inner rows
for (i = 1; i <= boardSize; i++)
{
matrix[i] = (cell *) malloc((boardSize + 1) * sizeof(cell));
// first letter each row
matrix[i][0].type = (char *) malloc(3 * sizeof(char));
matrix[i][0].type[0] = (char) (BASE_ALPHABET + i);
// init cols
for (j = 1; j <= boardSize; j++)
{
matrix[i][j].type = (char *) malloc(2 * sizeof(char) + 1);
matrix[i][j].type[0] = EMPTY;
matrix[i][j].type[1] = WATER; // default status
matrix[i][j].hidesShip = NULL;
}
}
return matrix;
}
Deallocations :
void freeMatrix(cell **matrix, int boardSize)
{
int k, l;
for (k = 0; k <= boardSize; k++)
{
for (l = 0; l <= boardSize; l++)
{
free(matrix[k][l].type);
}
free(matrix[k]);
}
free(matrix);
}
I run the code above(malloc + free are showed) and then checked memory-leak with Valgrind and got this output :
Valdrind Log
Any idea what I am doing wrong here? The Valgrind means I did one extra free command? I cant see where exactly because I moved over all cells.. maybe better understanding of pointers is required here? thanks.
matrix[0][k].type = (char *) malloc(3 * sizeof(char));
matrix[0][k].type = arrNo[k - 1];
The problem is that you are allocating memory and immidiatly after you write to the pointer holding the address. You can no longer access the memory therefore valgrind reports it as leaked.
You probably wanted to write
matrix[0][k].type[0] = arrNo[k - 1];
Assuming that arrNo is a character array, the first assignment would be illegal since you are assigning char to char *. Your compiler should have given you a warning.
I'm using an example from https://phoxis.org/2012/07/12/get-sorted-index-orderting-of-an-array/ where he returns the sort indices from a sort of an array, i.e.
3,4,2,6,8 returns 4,3,1,0,2 (+1 for each index in R). This is the equivalent of R's order function
I've translated his/her code to work as a function returning an array of sorted indices. The code gives the correct answer.
keeping track of the original indices of an array after sorting in C has a similar response, but as #BLUEPIXY warns, his solution doesn't work in all circumstances. I need something that will work in all circumstances, including ties.
however, the original author uses a global pointer, which causes a memory leak, and free() doesn't fix it. which I don't know how to do this without the global pointer.
How can I fix this memory leak, or at least return sorted indices in C that will always work?
#include <stdio.h>
#include <stdlib.h>
/* holds the address of the array of which the sorted index
* order needs to be found
*/
int * base_arr = NULL;
/* Note how the compare function compares the values of the
* array to be sorted. The passed value to this function
* by `qsort' are actually the `idx' array elements.
*/
static int compar_increase (const void * a, const void * b) {
int aa = *((int * ) a), bb = *((int *) b);
if (base_arr[aa] < base_arr[bb]) {
return 1;
} else if (base_arr[aa] == base_arr[bb]) {
return 0;
} else {
// if (base_arr[aa] > base_arr[bb])
return -1;
}
}
int * order_int (const int * ARRAY, const size_t SIZE) {
int * idx = malloc(SIZE * sizeof(int));
base_arr = malloc(sizeof(int) * SIZE);
for (size_t i = 0; i < SIZE; i++) {
base_arr[i] = ARRAY[i];
idx[i] = i;
}
qsort(idx, SIZE, sizeof(int), compar_increase);
free(base_arr); base_arr = NULL;
return idx;
}
int main () {
const int a[] = {3,4,2,6,8};
int * b = malloc(sizeof(int) * sizeof(a) / sizeof (*a));
b = order_int(a, sizeof(a) / sizeof(*a));
for (size_t i = 0; i < sizeof(a)/sizeof(*a); i++) {
printf("b[%lu] = %d\n", i, b[i]+1);
}
free(b); b = NULL;
return 0;
}
A straightforward approach without using a global variable can look the following way
#include <stdio.h>
#include <stdlib.h>
int cmp_ptr(const void *a, const void *b)
{
const int **left = (const int **)a;
const int **right = (const int **)b;
return (**left < **right) - (**right < **left);
}
size_t * order_int(const int *a, size_t n)
{
const int **pointers = malloc(n * sizeof(const int *));
for (size_t i = 0; i < n; i++) pointers[i] = a + i;
qsort(pointers, n, sizeof(const int *), cmp_ptr);
size_t *indices = malloc(n * sizeof(size_t));
for (size_t i = 0; i < n; i++) indices[i] = pointers[i] - a;
free(pointers);
return indices;
}
int main( void )
{
const int a[] = { 3,4,2,6,8 };
const size_t N = sizeof(a) / sizeof(*a);
size_t *indices = order_int(a, N);
for (size_t i = 0; i < N; i++) printf("%d ", a[indices[i]]);
putchar('\n');
free(indices);
return 0;
}
The program output is
8 6 4 3 2
As for the memory leak then it is due to overwriting the value of the pointer to redundantly allocated memory.
int * b = malloc(sizeof(int) * sizeof(a) / sizeof (*a));
b = order_int(a, sizeof(a) / sizeof(*a));
The memory allocation does not make sense.
The problem I see is that within main function - you are allocating pointer b some memory -
int * b = malloc(sizeof(int) * sizeof(a) / sizeof (*a));
The next line calls order_int(...) that returns a pointer to already allocated memory -
b = order_int(a, sizeof(a) / sizeof(*a));
Looking at the order_int function -
int * order_int (const int * ARRAY, const size_t SIZE) {
int * idx = malloc(SIZE * sizeof(int));
base_arr = malloc(sizeof(int) * SIZE);
for (size_t i = 0; i < SIZE; i++) {
base_arr[i] = ARRAY[i];
idx[i] = i;
}
qsort(idx, SIZE, sizeof(int), compar_increase);
free(base_arr); base_arr = NULL;
return idx;
}
.. you see that idx has been already been allocated the correct memory.
I would suggest removing the malloc from b - see below.
int * b = NULL;
So today's exercise is to create a function to initialize an array of int and fill it from 0 to n.
I wrote this :
void function(int **array, int max)
{
int i = 0;
*array = (int *) malloc((max + 1) * sizeof(int));
while (i++ < max)
{
*array[i - 1] = i - 1; // And get EXC_BAD_ACCESS here after i = 2
}
}
After a few hours of EXC_BAD_ACCESS I was getting crazy I decided to search on SO, find this question : Initialize array in function
Then changed my function to :
void function(int **array, int max)
{
int *ptr; // Create pointer
int i = 0;
ptr = (int *) malloc((max + 1) * sizeof(int)); // Changed to malloc to the fresh ptr
*array = ptr; // assign the ptr
while (i++ < max)
{
ptr[i - 1] = i - 1; // Use the ptr instead of *array and now it works
}
}
And now it works ! But it's not enough to have it working, I would really like to know why my first approach didn't work ! To me they look the same !
PS : just in case this is the main I use :
int main() {
int *ptr = NULL;
function(&ptr, 9);
while (*ptr++) {
printf("%d", *(ptr - 1));
}
}
You have the wrong precedence,
*array[i - 1] = i - 1;
should be
(*array)[i - 1] = i - 1;
Without the parentheses, you access
*(array[i-1])
or array[i-1][0], which is not allocated for i > 1.