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.
Related
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!
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.
The dynamicRandomMatrix function should return a pointer to an array of n pointers each of which points to an array of n random integers.
I got it to print mostly correct, except the first number in the array. This is the output:
n=3: -2084546528, 59, 45
Can anyone help me figure out why the first number in the array is so small? I think it must be something to do with local variables and access or something, but I am not sure.
int** dynamicRandomMatrix(int n){
int **ptr;
ptr = malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
int *address = randomArray(n);
ptr[i] = address;
}
return ptr;
free (ptr);
}
int* randomArray(int n){
int *arr;
arr = malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
int num = (rand() % (100 - 1 + 1)) + 1;
arr[i] = num;
}
return arr;
free(arr);
}
int main(){
int **ptr;
int i;
ptr = dynamicRandomMatrix(3);
printf("n=3: ");
for (i = 0; i < 3; i++) {
printf("%d, ", *ptr[i]);
}
return 0;
}
In your code,
ptr = malloc(sizeof(int) * n);
is not correct, each element in ptr array is expected to point to a int *, so it should be ptr = malloc(sizeof(int*) * n);. To avoid this, you can use the form:
ptr = malloc(sizeof(*ptr) * n);
That said, all your free(array); and free (ptr); are dead code, as upon encountering an unconditional return statement, code flow (execution) returns to the caller, and no further execution in that block (function) takes place. Your compiler should have warned about this issue. If not, use proper flags to enbale all warnings in your compiler settings.
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;
I am working on a custom malloc and free implementation in C. My code works fine, but not perfectly. In my file that tests my_malloc and my_free, I call my_malloc 3 times. It works for the first 2 calls, but doesn't for the 3rd call. Everything is exactly the same, so I really have no idea why it wouldn't work again. I know there's enough memory in the heap, so it's not that. It even works to the point of returning an address for the pointer variable, but the test file won't write to it.
Here's the bit of code to test my_malloc and my_free, it breaks with c:
static int *base;
static int *heap_end;
int total_mem_used = 0;
int first_call = 1;
int i;
int *a, *b, *c;
if ((a=(int *)my_malloc(10))==NULL)
return MALLOC_FAIL;
for (i=0;i<10;i++)
a[i] = i;
for (i=0;i<10;i++)
printf("%d\n", a[i]);
if ((b=(int *)my_malloc(18))==NULL)
return MALLOC_FAIL;
for (i=0;i<18;i++)
b[i] = i*i;
for (i = 0; i < 18; i++)
printf("%d ", b[i]);
printf("\n");
if ((c=(int *)my_malloc(5))==NULL)
return MALLOC_FAIL;
for (i=0;i<5;i++)
c[i] = i*7;
Here's my_malloc too, if it helps:
void *p;
int *t;
int data_size, block;
if (size==0)
return NULL;
if (first_call) {
if ((base=(int *)malloc(HEAP_SIZE))==NULL)
return NULL;
init_heap(norm_size(size)+8);
heap_end = &base[HEAP_SIZE];
first_call = 0;
total_mem_used += (norm_size(size)+2);
t = base;
return (void *) (t+2);
}
data_size = norm_size(size);
block = data_size + 2;
p = find_first_free(block);
if (p==0) {
errno = ENOMEM;
return NULL;
}
total_mem_used += block;
fill_header((int *) p, block);
t = (int *) p + 2;
return (void *) t;
void my_free(void *p) {
int *t;
t = (int *) p - 2;
*t = *t & -2;
coalesce(t);
}
void *find_first_free(int n) {
int *p;
p = base;
while (p<heap_end && ((*p & 1) || (*p <= n)))
p = p + (*p & -2);
return (void *)p;
}
int norm_size(int w) {
if (w % 8 == 0)
return w;
else
return w + (8 - w % 8);
}
void init_heap(int n) {
base[0] = n+1; // n+1 since we're allocating it
base[1] = (int) &base[n];
base[n-1] = n+1;
base[n] = HEAP_SIZE - n;
base[HEAP_SIZE-1] = HEAP_SIZE - n;
}
void fill_header(int *p, int w) {
p[0] = w+1;
p[1] = (int) &p[w];
p[w-1] = w+1;
p[w] = HEAP_SIZE - total_mem_used;
p[w+HEAP_SIZE-total_mem_used-1] = HEAP_SIZE - total_mem_used;
}
Any idea what exactly is wrong with the program? Thanks for any help.
Avoid magic numbers
block = data_size + 2;
Why 2? why not 16 or 256? Certainly the addition is done to provide for saving the size. In that case, add the size of the int.
block = data_size + sizeof(int);
t = (int *) p + 2;
Why 2 versus any other number? Again, this is done to account for the size begin saved at p. But this is not integer addition like before. This is "pointer addition". With + 2, p is increased by the 2 * sizeof(int). Likely code should be
t = p + 1;
This is an exception to the "no magic numbers" rule: -1,0,+1 are OK
To answer more, post complete functions.
Minor: cast not needed
// if ((base=(int *)malloc(HEAP_SIZE))==NULL)
if ((base = malloc(HEAP_SIZE)) == NULL)
Minor: Consider the unsigned type size_t. That is the type returned by functions/operators like strlen(), sizeof()
// int data_size
size_t data_size
// if ((a=(int *)my_malloc(10))==NULL)
a = my_malloc(10);
if (a == NULL)
Why 8 in init_heap(norm_size(size)+8);? Use a constant/define
#define MY_MALLOC_GUARD (8)
init_heap(norm_size(size) + MY_MALLOC_GUARD);