Consider the code below:
#include < stdio.h >
#include < stdlib.h >
#define SIZE 10
int main() {
int * p, i;
p = malloc(SIZE * sizeof(int));
if (p == NULL) {
printf("malloc failed.\n");
return 1;
}
for (i = 0; i < SIZE; i++)
* (p + i) = i * i;
for (i = 0; i < SIZE; i++)
printf("%d\n", * p++);
free(p);
return 0;
}
This code doesn't work. However I am not sure why. My professor gave an explanation that doesn't make much sense to me. Supposedly the free function doesn't work.
From what I understand, you can only free pointers that were created using malloc. And here we modify that pointer before sending it to free, thereby making our statement invalid.
Is this the correct way to critique that code?
And here we modify that pointer before sending it to free, thereby making our statement invalid.
Is this the correct way to critique that code?
Yes, code is not freeing the original pointer allocated due to p++ which increments the pointer with each loop iteration.
Instead, print in such a way p is not changed.
for (i = 0; i < SIZE; i++) {
// printf("%d\n", * p++);
printf("%d\n", p[i]);
// or
printf("%d\n", * (p + i));
}
// With above change, `p` is the same as the original allocated value.
free(p);
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!
I've been trying O(n ^2) sorting algorithm just to practice C, but have encountered this annoying "realloc(): invalid pointer" error and cannot figure out why. I've viewed other explanations but they have not helped too much.
#include <stdio.h>
#include <stdlib.h>
int* removeIndex(int* list, int index, int len){
for(int i = index; i < len - 1; i++){
list[i] = list[i+1];
}
return realloc(list, len - 1);
}
int* sort(int* unsorted, int len){
int* sorted = malloc(len * sizeof(int));
for(int placement = 0; placement < len; placement++){
int smallest_index = 0;
int smallest = unsorted[smallest_index];
int len_unsorted = len - placement;
for(int i = 0; i < len_unsorted; i++){
if (unsorted[i] < smallest){
smallest = unsorted[i];
smallest_index = i;
}
}
unsorted = removeIndex(unsorted, smallest_index, len_unsorted);
sorted[placement] = smallest;
}
return sorted;
}
int main()
{
int len = 5;
int unsorted[5] = {5,4,3,2,1};
int* sorted = sort(unsorted, len);
for(int i = 0; i < len; i++){
printf("%d\n", sorted[i]);
}
return 0;
}
On a side note, why do I get an error if I write
int len = 5;
int unsorted[len] = {5,4,3,2,1};
so I have to force write it as int unsorted[5] = {5,4,3,2,1};
Cheers
The pointer passed to realloc pointing to a array with auto storage duration, which is declared and initialized in main(), and not pointing to a memory block previously allocated with malloc, calloc or realloc.
From realloc [emphasis added]
Reallocates the given area of memory. It must be previously allocated by malloc(), calloc() or realloc() and not yet freed with a call to free or realloc. Otherwise, the results are undefined.
On top of the answer of H.S., I believe the sorting algorithm is ill designed. The first call to the function removeIndex is done with the parameters as so
removeIndex(unsorted, 4, 5)
The for loop is not entered and a reallocation is supposed to take place with realloc(list, 4).
As far as I can see the sorting algorithm cannot work in general. In particular the example you gave with 5,4,3,2,1.
Try to do that with pencil and paper and you will see what I mean.
I couldn't understand the first and second value of the output, why are they different ? What is the second output meaning here ?
The Code is:
int **p = (int **)malloc(sizeof(int *) * 2);
int i, j, c = 1;
for (i = 0; i < 2; i++) {
p[i] = (int *)malloc(sizeof(int) * 2);
}
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
p[i][j] = c++;
}
}
printf("%d %d %d %d\n", (int)&p[0][0], (int)p, (int)*p, **p);
Output: 34439216 34439184 34439216 1
Alright. Let's talk about some basic issues first:
On many systems, int will take up less room than void *. So you're possibly truncating your pointers when you print them. It's quite easy to fix that, so let's do it.
Additionally, it's unnecessary to cast the value of malloc(), so let's get rid of that as well to clean up the code a bit.
Finally, as chris notes, to use the %p format specifier, we need to cast the int ** and int * variables to void *.
Fixed foo.c
#include <stdio.h>
#include <stdlib.h>
int main() {
int **p = malloc(sizeof(int *) * 2);
int i, j, c = 1;
for (i = 0; i < 2; i++)
p[i] = malloc(sizeof(int) * 2);
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++)
p[i][j] = c++;
printf("%p %p %p %d\n", (void *) &p[0][0], (void *) p, (void *) *p, **p);
}
Which now outputs:
0x7fd193c03930 0x7fd193c03920 0x7fd193c03930 1
So now, your actual question:
First, let's talk about what address &p[0][0] points to. That's a fairly complicated expression, but we can reduce it using a fairly simple process such that we end up with *p or p[0].
&p[0][0] == &*(p[0] + 0) == p[0] + 0 == p[0] == *(p + 0) == *p
Looking at that, it should be pretty clear why &p[0][0] (the first argument) and *p (the third argument) print the same value.
Now, I don't see any good reason why p[0] should point to the same address as p. p and p[0] have been assigned values from separate calls to malloc().
For this code
#include <stdlib.h>
#include <stdio.h>
int *f (int n)
{
int *ptr = malloc (sizeof (int));
*ptr = n;
return ptr;
}
int main()
{
int i;
int **ptr = malloc (sizeof (int *));
ptr[0] = f (0);
for (i = 0; i < 5; ++i)
{
ptr = realloc (sizeof (int *) * (i + 2));
ptr[i + 1] = malloc (sizeof (int));
ptr[i + 1] = f (i + 1);
}
for (i = 0; i < 5; ++i)
{
printf ("%d\n", *ptr[i]);
free (ptr[i]);
}
free (ptr);
return 0;
}
does program allocate twice than it is needed?
Yes, You don't need the malloc in main as it is immediately overwritten on the next line and you leak that memory. Is this a homework question?
EDIT for question change
This is now leaking memory in an odd way.
The first few lines aren't leaking but when you get into the loop you're allocating and assigning randomly. (As a first, realloc takes as it's first arguement a pointer to reallocate, so you're missing ptr in there)
Now you're allocating ptr to be of size 2, then 3 then 4 etc... up to 6. And then immediately leaking that memory as you overwrite the pointer with the call to f()
You could write that all like this:
int i;
int **ptr = malloc (sizeof(int*) * 6);
for (i = 0; i < 6; ++i)
{
ptr[i] = f(i);
}
for (i = 0; i < 6; ++i)
{
printf ("%d\n", *ptr[i]);
free (ptr[i]);
}
free (ptr);
return 0;
As an aside, you should in general try not to allocate memory too often, it is relatively slow. If you can use the stack you should, and if not, try and allocate all the memory you need up front, calling realloc in a loop is a bad idea and should be avoided.
In this specific case you don't need a pointer to a pointer, you could have just allocated one array of 6 integers, with int* array = malloc(sizeof(int) * 6) and then array[0] = 0; which would be easier and better.
Yes, it does allocate twice the needed memory. Also, the value of "ptr" in main is overwrite by return of "f" so you don't even have a chance to free it. You could remove the call to malloc in "main":
int main()
{
int *ptr = f (3);
printf ("%d\n", *ptr);
free (ptr);
return 0;
}
I've just started C read the man page but could not find the proper answer. So the code is below
void *p = malloc(10*sizeof(int));
int *q = p;
int NUMOFINT = 10;
for (int i = 0; i < NUMOFINT; i++){
printf("%i ", q[i]);
}
void *realloc(void *p, 20*sizeof(int));
for (int i = 0; i < 21; i++){
printf("%i ", q[i]);
and it is giving this error:
malloc.c: In function ‘main’:
malloc.c:31:24: error: expected declaration specifiers or ‘...’ before numeric constant
I did not quite understand that the size format was ok for malloc() but not ok for realloc. So how do I correct the error?
Edit:
so when I make it as:
void *morep = realloc(p, 20*sizeof(int));
int *q2 = morep;
for (int i = 0; i < 20; i++){
printf("%i ", q2[i]);
}
it prints out q2[11] as 135121
This
void *realloc(void *p, 20*sizeof(int));
is wrong. You want
p = realloc(p, 20*sizeof(int));
Incidentally, this line is also a problem (but will compile fine):
for (int i = 0; i < 21; i++){
You allocated p to 20*sizeof(int) bytes, so element 20 is past the end of the array. You want:
for (int i = 0; i < 20; i++){
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int *temp; /* To use with realloc, it's more secure */
void *p = malloc(10*sizeof(int));
int *q = p;
int NUMOFINT = 10;
/* dont forget to compile with -std=99 flag, if you use this kind of for loop */
for (int i = 0; i < NUMOFINT; i++){
printf("%i ", q[i]);
}
printf("\n");
/* It's more secure to use this kind of realloc */
temp = realloc (p, 20 * sizeof(int) );
if (temp == NULL)
{
fprintf(stderr,"Reallocation failed --> %s\n", strerror(errno));
free(p);
exit(EXIT_FAILURE);
}
else
{
p = temp;
}
/* Zeroing after realloc */
for (int i = NUMOFINT; i < 21; i++)
q[i] = 0;
for (int i = 0; i < 21; i++)
{
printf("%i ", q[i]);
}
printf("\n");
return 0;
}
realloc can tries to expand the existing memory block in heap, if its not possible it will allocate a new separate block of memory for the new size and it will copy the data from old memory block to the new memory block also.
So if realloc returns the address same as p then it just expands the old memory block. Or else we have to free the old memory block and start using the new memory block returned by realloc.
#define NUMOFINT 10
#define NUMOFINT_NEW 20
void *p = malloc(NUMOFINT * sizeof(int));
int *q = p;
void *temp = NULL;
for (int i = 0; i < NUMOFINT; i++)
{
printf("%i ", q[i]);
}
temp = realloc(p, NUMOFINT_NEW * sizeof(int));
if (temp == NULL)
{
exit(0);
}
else if (temp != p)
{
free(p);
p = temp;
}
//else temp is equal to p
for (int i = 0; i < NUMOFINT_NEW; i++)
{
printf("%i ", q[i]);
}
Here q[0] to q[9] will have the values(0, 1, 2..9) assigned, and the rest (q[10] to q[19]) will have garbage value. We have not memset the newly allocated memory to 0 also.
you can memset also before for loop,
memset((q + NUMOFINT), 0, (NUMOFINT_NEW - NUMOFINT));
Mistakes in your program are
1) compilation error because
void *realloc(void *p, 20*sizeof(int)); This statement doesn;t looks like a function call.
2) for (int i = 0; i < 21; i++) - After memory is realloced to 20 elements, you can access only upto 19th, accessing 20th may leads to crash(undefined behaviour).
3) it prints out q2[11] as 135121 - Newly reallocated memory is neither memset to 0 nor assigned any meaningful values.