I've been trying to make an example program using calloc and realloc and I've come across an issue where, when I make an array of integers smaller, it seems to remove the first element instead of the last one.
int *m = (int*)calloc(2, sizeof(int));
*m = 1;
*(m+1) = 2;
printf("\tInt 1: %d\n", m[0]);
printf("\tInt 2: %d\n\n", *(m+1));
// REALLOC
printf("How many elements the array have? ");
scanf("%d", &num);
*m = (int *)realloc(m, num * sizeof(int));
printf("ARRAY NOW HAS %d PLACES\n\n\t", num);
for(i = 0; i < num; i++) {
m[i] = i + 1;
printf("%d ", m[i]);
}
// DELETING MEMBERS OF AN ARRAY
while((d < 0) || (d > num)) {
printf("\n\nChoose which position of the previous array should be deleted (0 = first): ");
scanf("%d", &d);
}
printf("\nUPDATED ARRAY:\n\n");
for(i = d; i < num - 1; i++) {
m[i] = m[i + 1];
}
*m = (int *)realloc(m, (num - 1)*sizeof(int));
num--;
for(i = 0; i < num; i++) {
printf("%d ", m[i]);
}
An example of the program output would be:
Int 1: 1
Int 2: 2
How many elements the array have? 17
ARRAY NOW HAS 17 PLACES
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Choose which position of the previous array should be deleted (0 = first): 6
UPDATED ARRAY:
10620272 2 3 4 5 6 8 9 10 11 12 13 14 15 16 17
And if I include the last member of the array that should have been deleted (in this case m[16]) it shows:
10620272 2 3 4 5 6 8 9 10 11 12 13 14 15 16 17 17
Of course, I'm not entirely sure what's happening but it seems like it's just removing the value of m[0]?
Thanks in advance for any help!
The reason the initial value gets modified is that you are assigning it:
*m = (int *)realloc(m, num * sizeof(int));
should be
m = realloc(m, num * sizeof(int));
Your code should also produce a warning, telling you that an assignment of a pointer to an array element containing ints is invalid. Fixing this warning should have fixed your problem.
Note that an assignment of the form
m = realloc(m, ...);
where m is used on both sides of realloc is inherently unsafe, because realloc could potentially return NULL - for example, when there is not enough memory to allocate. Blind assignment to m would render the old value of m inaccessible, preventing proper deallocation. In production you should assign realloc's result to a temporary, then check it for NULL, and only then assign the result back to m.
In addition to #dasblinkenlight good answer, when reducing the allocation size and the re-allocation fails (a rare event), code can simple continue with the original pointer.
Suggested re-write, assuming num > 0:
// *m = (int *)realloc(m, num * sizeof(int));
void *t = realloc(m, sizeof *m * num);
if (t) {
m = t;
}
Related
Here I'm trying to allocate the memory dynamically to create multi-dimensional.
So I declared a pointer to pointer to pointer :
int ***array ;
And allocated memory for variable array
array = (int***)malloc((sizeof(int) * 2));
This is my code !
void main(void)
{
int matrices, rows, columns;
int ***array;
printf("\n\n HOW MANY MATRICES YOU TO CREATE ? : ");
scanf("%d",&matrices);
array = (int***)malloc((sizeof(int) * matrices));
printf("\n HOW MANY ROWS YOU TO CREATE ? : ");
scanf("%d",&rows);
printf("\n HOW MANY COLUMNS YOU TO CREATE ? : ");
scanf("%d",&columns);
for(int i = 1; i <= matrices; i++)
{
printf("\n Enter %d - matrix! ",i);
for(int j = 1; j <= columns; j++)
{
for(int k = 1; k <= rows; k++)
{
printf("\n Enter element [%d[%d] : ",j,k);
scanf("%d",&array[i][j][k]);
}
}
}
//printing two matrices elements!!!
for(int l = 1; l <= matrices; l++)
{
printf("\n MATRIX - %d !! \n",l);
for(int m = 1; m <= columns; m++)
{
for(int n = 1; n <= rows; n++)
{
printf("%d\t",array[l][m][n]);
}
printf("\n");
}
}
}
But when I try to print the elements of the both matrices, here only second matrix elements are displayed on output for both matrices and very first element in both matrices are displayed with ' 0 ' .
Example :
Input :
First matrix
1 2 3
4 5 6
second matrix
9 8 7
3 5 2
Output :
First matrix
0 8 7
3 5 2
second matrix
0 8 7
3 5 2
I'm new to this site, any mistakes please comment !!
Just use Variable Length Array (VLA) with dynamic storage.
int (*array)[rows + 1][cols + 1] = malloc(sizeof(int[matrices + 1][rows + 1][cols + 1]));
Using VLAs is a lot simpler and more performant.
Adding 1 to each dimension let you address array from index 1 and prevents program from Undefined Behaviour (UB) when accessing element array[matrixes][rows][cols].
However, it is BAD practice because arrays in C are indexed from 0. Other approach will confuse other users of your code.
Therefore, I strongly encourage you to index arrays from 0 and remove all "+ 1"s.
So the correct allocation code should be:
int (*array)[rows][cols] = malloc(sizeof(int[matrices][rows][cols]));
And update all loops to form:
for(i = 0; i < matrices ; i++)
Finally, free the array when it is no longer used.
free(array)
You have not SegFaulted only by happy accident, and due to the fact that the size of a pointer doesn't change. So where you allocate for int* where you should be allocating for int**, the size of your allocation isn't affected (by happy accident...)
You generally want to avoid becoming a 3-Star Programmer, but sometimes, as in this case, it is what is required. In allocating for any pointer, or pointer-to-pointer, or in this case a pointer-to-pointer-to-pointer, understand there is no "array" involved whatsoever.
When you declare int ***array; you declare a single pointer. The pointer then points to (holds the address of) a block of pointers (type int**) that you allocate. You allocate storage for matricies number of int** pointers as input by the user.
Each matrix is type int**, so you must allocate a block of memory containing rows number of pointer for each matrix.
Finally you allocate cols number of int (type int*) for each and every row in each and every matrix.
So your collection of matricies is an allocated block of pointers with one pointer for each matrix. Then each matrix is an allocate block of pointers with one pointer for every row in that matrix. Finally you allocate a columns worth of int for each an every row pointer for each and every matrix.
Visually your allocation and assignment would resemble the following:
array (int***)
|
+ allocate matricies number of [Pointers]
|
+----------+
| array[0] | allocate rows number of [Pointers] for each matrix
+----------+ assign to each pointer in array block
| array[1] |
+----------+ array[2] (int**)
| array[2] | <======= +-------------+
+----------+ | array[2][0] |
| .... | +-------------+ allocate cols no. of [int]
| array[2][1] | for each allocated row pointer
+-------------+
| array[2][2] | <=== array[2][2] (int*)
+-------------+ +----------------+
| ... | | array[2][2][0] |
+----------------+
| array[2][2][1] |
+----------------+
| array[2][2][2] |
+----------------+
| ... |
In order to always keep the type-size of each allocation correct, simply use the dereferenced pointer to set the type-size. For example when allocating for array (int***) you would use:
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
When allocating for each array[i], you would use:
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
Finally when allocating for each block of int for each row, every array[i][j], you would use:
array[i][row] = malloc (cols * sizeof *array[i][row]);
If you always use the dereference pointer to set type-size, you will never get it wrong.
Following the diagram above through and just taking each allocation in turn (and validating EVERY allocation), you could write your allocation and free routines similar to:
/* use dereferenced pointer for type-size */
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
if (!array) { /* validate EVERY allocation */
perror ("malloc-array");
return 1;
}
for (int i = 0; i < matrix; i++) {
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
if (!array[i]) { /* validate */
perror ("malloc-array[i]");
return 1;
}
for (int row = 0; row < rows; row++) {
/* allocate cols int per-row in each matrix */
array[i][row] = malloc (cols * sizeof *array[i][row]);
if (!array[i][row]) {
perror ("malloc-array[i][row]");
return 1;
}
}
}
The complete example that allocates for the number of matricies with the number of rows and columns entered by the user would be:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int ***array = NULL,
matrix,
rows,
cols;
fputs ("no. of matricies: ", stdout);
if (scanf ("%d", &matrix) != 1) /* validate EVERY input */
return 1;
fputs ("no. of rows : ", stdout);
if (scanf ("%d", &rows) != 1) /* ditto */
return 1;
fputs ("no. of cols : ", stdout);
if (scanf ("%d", &cols) != 1) /* ditto */
return 1;
/* use dereferenced pointer for type-size */
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
if (!array) { /* validate EVERY allocation */
perror ("malloc-array");
return 1;
}
for (int i = 0; i < matrix; i++) {
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
if (!array[i]) { /* validate */
perror ("malloc-array[i]");
return 1;
}
for (int row = 0; row < rows; row++) {
/* allocate cols int per-row in each matrix */
array[i][row] = malloc (cols * sizeof *array[i][row]);
if (!array[i][row]) {
perror ("malloc-array[i][row]");
return 1;
}
}
}
/* fill matricies with any values */
for (int i = 0; i < matrix; i++)
for (int j = 0; j < rows; j++)
for (int k = 0; k < cols; k++)
array[i][j][k] = j * cols + k + 1;
/* display each matrix and free all memory */
for (int i = 0; i < matrix; i++) {
printf ("\nmatrix[%2d]:\n\n", i);
for (int j = 0; j < rows; j++) {
for (int k = 0; k < cols; k++)
printf (" %2d", array[i][j][k]);
putchar ('\n');
free (array[i][j]); /* free row of int (int*) */
}
free (array[i]); /* free matrix[i] pointers (int**) */
}
free (array); /* free matricies pointers (int***) */
}
(note: you free the memory for each block of int before freeing the memory for the block of row pointers in each matrix before freeing the block of pointers to each matrix)
Example Use/Output
$ ./bin/allocate_p2p2p
no. of matricies: 4
no. of rows : 4
no. of cols : 5
matrix[ 0]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 1]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 2]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 3]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/allocate_p2p2p
==9367== Memcheck, a memory error detector
==9367== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9367== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==9367== Command: ./bin/allocate_p2p2p
==9367==
no. of matricies: 4
no. of rows : 4
no. of cols : 5
matrix[ 0]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 1]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 2]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 3]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
==9367==
==9367== HEAP SUMMARY:
==9367== in use at exit: 0 bytes in 0 blocks
==9367== total heap usage: 23 allocs, 23 frees, 2,528 bytes allocated
==9367==
==9367== All heap blocks were freed -- no leaks are possible
==9367==
==9367== For counts of detected and suppressed errors, rerun with: -v
==9367== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
Since you are using pointer to pointer to pointer. You need to dynamically allocate memory at all stages. At the first stage after you've asked number of matrices. It should be,
array = (int***)malloc (sizeof(int**) * matrices);
Since you are allocating matrices which are int**. Then after asking number of rows, for each matrix you need to allocate that,
for(i=1 ; i <= matrices ; i++)
array[i-1] = (int**)malloc (sizeof(int*)*ROWS);
Finally you need to allocate memory for each row. So,
for(i=1 ; i <= matrices ; i++)
for(j=1 ; j <= ROWS ; j++)
array[i-1][j-1] = (int*)malloc (sizeof(int)*COLS);
After this you can take inputs at your leisure the way you did. Try this, it should work. If it doesn't, there should be some other problem.
In C, avoid the model of
pointer = (some_type *) malloc(n * sizeof(some_type)); // Avoid
Instead of allocating to the type, allocate to the referenced object and drop the unneeded cast. Form the size computation with the widest type first. sizeof operator returns a type of size_t.
pointer = malloc(sizeof *pointer * n); // Best
This is simpler to code right (OP's (sizeof(int) * matrices) was incorrect and too small), review and maintain.
Robust code check for allocation errors.
if (pointer == NULL) {
fprintf(stderr, "Out of memory\n"); // Sample error code, adjust to your code's need
exit(-1);
}
Allocate memory for the matrix data, something OP's code did not do.
array = malloc(sizeof *array * matrices);
// Error checking omitting for brevity, should be after each malloc()
// Use zero base indexing
// for(int i = 1; i <= matrices; i++) {
for (int m = 0; m < matrices; m++) {
array[m] = malloc(sizeof *array[m] * rows);
for (int r = 0; r < rows; r++) {
array[m][r] = malloc(sizeof *array[m][r] * columns);
}
}
// Now read in data
// Use data
// Free when done
for (int m = 0; m < matrices; m++) {
for (int r = 0; r < rows; r++) {
free(array[m][r]);
}
free(array[m]);
}
free(array);
Better code would use size_t for the array dimension's type than int, yet int will do for small programs.
The goal of this program is to add the first and last elements of an array together and set that value as the first element of an output array, and then continue moving inwards as such. All of the sums will be stored in an output array. For this program, the rules stipulate that I may only use pointers and pointer arithmetic (i.e. no subscripting, no '[]', etc.) I have gotten the program to work for arrays of length 2 as well and length 4 (as I have only implemented functionality for even-lengthed arrays) however when I try any array of length 6 or above, the program adds together incorrect values that are not in the first array.
I have already tried using two different debuggers to isolate where the problem is coming from and for the life of me I can not figure it out. I have spent a few hours looking over my notes on C and going through the code, reworking it however I can. I feel as if there is something wrong with how I am interacting between the array and the pointer variables, but I am unsure. I couldn't seem to find any questions on Stack Overflow too similar to this one (yes, I looked).
void add(int *a1, int array_size, int *a2) {
int * p;
int * temp = (a1+(array_size-1));
if (array_size % 2 == 0) {
array_size = array_size/2;
for (p = a2; p < (a2+array_size); p++) {
*p = *a1 + *temp;
printf("%d", *a1);
printf(" + %d", *temp);
a1++;
temp--;
printf(" = %d\n", *p);
}
}
}
For arrays of length 2 and 4 (again, I am only testing even numbers for now), the code works fine.
Example Output:
Enter the length of the array: 2
Enter the elements of the array: 1 2
1 + 2 = 3
The output array is: 3
Enter the length of the array: 4
Enter the elements of the array: 1 2 3 4
1 + 4 = 5
2 + 3 = 5
The output array is: 5 5
Now this is where it is going wrong.
When I do this:
Enter the length of the array: 6
Enter the elements of the array: 1 2 3 4 5 6
I expect:
1 + 6 = 7
2 + 5 = 7
3 + 4 = 7
The output array is: 7 7 7
But instead, the output is:
1 + 0 = 1
2 + 3 = 5
3 + 4 = 7
The output array is: 1 5 7
My best guess is that something went wrong with my use of pointers or perhaps pointer syntax. Any help I can get, positive or negative, would be greatly appreciated.
This is the main() function:
int main() {
int size = 0;
int out_size = 0;
int arr[size];
printf("Enter the length of the array: ");
scanf("%d", & size);
printf("\nEnter the elements of the array: ");
for (int i = 0; i < size; i++) {
scanf("%d", & arr[i]);
}
if (size % 2 == 0) {
out_size = size/2;
}
else{
out_size = ((size-1)/2) + 1;
}
int out[out_size];
//calling the add function and using the addresses of arrays + array size
add(arr, size, out);
//iterating through and printing output array which has now been
//altered by the move function
printf("\nThe output array is: ");
for (int i = 0; i < out_size; i++) {
printf("%d ", out[i]);
}
return 0;
}
You are using an array of size 0:
int main() {
int size = 0;
int out_size = 0;
int arr[size]; // <- Here is your problem
You could move the array declarations after the size reading:
int main() {
int size = 0;
int out_size = 0;
printf("Enter the length of the array: ");
scanf("%d", & size);
int arr[size];
printf("\nEnter the elements of the array: ");
for (int i = 0; i < size; i++) {
scanf("%d", & arr[i]);
}
I've been at this problem for like 3 days and I've combed my entire code to try to figure out why I'm getting incorrect output. The purpose of this program is to do a merge sort using threads. The first part is simply sorting the elements in parallel into however many segments a user inputs. The only inputs tested will be 2, 5, and 10. And the array to be sorted will always be 50 int array of randomly generated numbers.My code works fine when the segments entered (denoted by the variable 'segments' at the top of main) is 2. However, when I change segments to 5 or 10, I don't get a sorted array at the end. I've tried debugging by using print statements (which I've commented out but you can still see) and there seems to be a problem during the first two merge iterations. For some reason the resulting of those merge iterations are not in order, and they contain duplicate numbers that don't exist in duplicate in the original array passed to it. My sorting method and merging methods work fine when I just pass arrays to them, and don't use threads but when I do use threads I get behavior that I can't explain. Below is my program in its entirety, to merge an array of 50 it should do the following:
split the array into 10 segments of 5, and sort each segment.
pass the segments in pairs, in rounds. So round one should pas segment 0-5 in one segment and 5-10 in another, 10-15 and 15-20, 20-25 and 25-30, and so on until it reaches 40-45 and 45-50.
then it will go into round two which does same thing as round one but it passes the segments in pairs of 10. So 0-10 and 10-20, 20-30 and 30-40, then it leaves the last part of 10 untouched
round three passes the segments to merge in pairs of 20: 0-20 and 20-40, then stops.
Finally it should merge the segments 0-40 with 40-50.
My program: (you should mainly focus on my main function, sort is fine, and merge seems fine too, but i've included them anyways just in case)
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <pthread.h>
/**
* Struct to contain an array partition as well as the size of the partition.
* Use struct to pass multiple parameters to pthread_create
*/
struct array_struct{
int *partition;
int size;
};
/**
* Struct that contains two arrays (should be sorted) to merge
* Use struct to pass multiple parameters to pthread_create
*/
struct arrays_to_merge{
int *array1;
int *array2;
int size1;
int size2;
};
//comparison function to use with qsort, sorts in ascending order
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
/**
* Method that takes a struct containing a pointer to the first int in an array
* partition, as well as the partition size. Object must be type void, used with pthread_create
* #param pointer to the partition object. Type void
*/
void *sort(void *object){
struct array_struct *structure;
structure = (struct array_struct *) object;
int *array = structure->partition;
int size = structure->size;
int *i, j = 0;
qsort(array, size, sizeof(int), cmpfunc);
printf("Sorted %d elements.\n", size);
}
void *merge(void * object){
struct arrays_to_merge *arrays_struct;
arrays_struct = (struct arrays_to_merge *) object;
int *array1 = arrays_struct->array1;
int *array2 = arrays_struct->array2;
int size1 = arrays_struct->size1;
int size2 = arrays_struct->size2;
int tempArray[size1 + size2];
int i = 0, j = 0, k = 0, duplicates = 0;
while (i < size1 && j < size2) {
// printf("Merge number : %d Comparing %d and %d\n", mergenumber, array1[i], array2[j]);
if (array1[i] <= array2[j]) {
// printf("Picking %d\n", array1[i]);
tempArray[k] = array1[i];
if (array1[i] == array2[j])
{
duplicates++;
}
i++;
k++;
}else {
// printf("Merge number : %d Picking %d\n", mergenumber, array2[j]);
tempArray[k] = array2[j];
k++;
j++;
}
}
while (i < size1) {
// printf("Merge number : %d left over Picking %d\n", mergenumber, array1[i]);
tempArray[k] = array1[i];
i++;
k++;
}
while (j < size2) {
// printf("Merge number : %d left over Picking %d\n", mergenumber, array2[j]);
tempArray[k] = array2[j];
k++;
j++;
}
array1 = arrays_struct->array1;
for(i = 0; i < size1 + size2; i++){
array1[i] = tempArray[i];
}
printf("Merged %d and %d elements with %d duplicates\n", size1, size2, duplicates);
}
//return an array of size 50 with randomly generated integers
int *randomArray(){
srand(time(NULL));
static int array[50];
int i;
for (i = 0; i < 50; ++i){
array[i] = rand() % 51;
}
return array;
}
int main(int argc, char const *argv[])
{
int segments = 10;//make equal to argv input after testing
pthread_t threads[segments];
int i, *numbers; //iterator i, and pointer to int array 'numbers'
numbers = randomArray(); //return an array of random ints and store in 'numbers'
struct array_struct array[segments];
for(i = 0; i < segments; i++){
int *partition = numbers + (i * (50/segments));//obtain the first index of partition
array[i].partition = partition;
array[i].size = 50/segments;
pthread_create(&threads[i], NULL, sort, (void *) &array[i]);
}
for(i = 0; i < segments; i++){
pthread_join(threads[i], NULL);
}
int count = segments;
struct arrays_to_merge arrays[segments];
int j;
int size = 50/ segments;
while(count > 1){
for(i = 0, j = 0; i < count-1; j++, i += 2){
int *partition = numbers + (i * (size));
int *partition2 = numbers + (i+1 * (size));
arrays[j].array1 = partition;
arrays[j].array2 = partition2;
arrays[j].size1 = size;
arrays[j].size2 = size;
pthread_create(&threads[j], NULL, merge, (void *) &arrays[j]);
}
for(i = 0; i < j; i++){
pthread_join(threads[i], NULL);
}
size = size * 2;
count = count/2;
}
if(segments != 2){//for segments = 2, no need for his
int *partition = numbers;
int *partition2 = numbers + (size);
arrays[0].array1 = partition;
arrays[0].array2 = partition2;
arrays[0].size1 = size;
arrays[0].size2 = 50 - size;
pthread_create(&threads[0], NULL, merge, (void *) &arrays[0]);
pthread_join(threads[0], NULL);
}
for(i = 0; i < 50; i++){
printf("%d\n", numbers[i]);
}
pthread_exit(NULL);
return 0;
}
this is my output:
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 10 and 10 elements with 3 duplicates
Merged 10 and 10 elements with 1 duplicates
Merged 20 and 20 elements with 7 duplicates
Merged 40 and 10 elements with 17 duplicates
0
6
9
11
12
13
13
14
15
17
19
23
25
25
25
26
26
28
28
28
28
30
32
32
32
34
39
41
41
44
44
44
44
44
50
50
9
15
50
9
15
19
26
50
50
9
15
11
14
50
Sorry for the long wall of text, I've tried resolving this on my own and after countless hairs pulled I can't figure it out. Please help me figure out what I'm doing wrong. I think my problem lies in either the way I'm joining threads, or my merge function but since I cant be sure, i just included the whole thing.
It took a while but finally I got there :)
The problem is with this line:
int *partition2 = numbers + (i+1 * (size));
which is equivalent to (due to operator precedence).
int *partition2 = numbers + (i + size);
and is not what you want.
It should be:
int *partition2 = numbers + ((i+1) * (size));
Notice the additional brackets. Without which, the partition2 index is calculated incorrectly. Hence, merging with different parts of the array.
I'm a beginner and I'm doing some exercises to learn C.
I'm working on dynamic memory allocation with structs and pointers. I have this struct:
struct fact_entry
{ /* Definition of each table entry */
int n;
long long int lli_fact; /* 64-bit integer */
char *str_fact;
};
And this is my main code:
int
main (int argc, char *argv[])
{
int n;
int i;
struct fact_entry *fact_table;
if (argc != 2)
panic ("wrong parameters");
n = atoi (argv[1]);
if (n < 0)
panic ("n too small");
if (n > LIMIT)
panic ("n too big");
/* Your code starts here */
int p;
fact_table = (struct fact_entry *)malloc(n*sizeof(struct fact_entry));
if(fact_table==NULL)
{
fprintf(stderr, "Out of memory, exiting\n");
exit(1);
}
for (i = 0; i<= n; i++)
{
fact_table[i].n = i;
p = i;
fact_table[i].lli_fact=1;
while(p>0)
{
fact_table[i].lli_fact = p * fact_table[i].lli_fact;
p--;
}
p = (int)log10(fact_table[i].lli_fact)+1;
fact_table[i].str_fact = malloc(p);
if(fact_table->str_fact==NULL)
{
fprintf(stderr, "Out of memory, exiting\n");
exit(1);
}
sprintf(fact_table[i].str_fact,"%lld",fact_table[i].lli_fact);
}
/* Your code ends here */
for (i = 0; i <= n; i++)
{
printf ("%d %lld %s\n", fact_table[i].n, fact_table[i].lli_fact,
fact_table[i].str_fact);
}
return 0;
}
The idea is to fill an array of 20 rows. Then every row have 3 columns. In the first column it shows the number of the line "i", in the second, the factorial of the number of the line, in the third the same that in the second but in string format.
I use the log10 to know how long will be the string.
The execution of the program shows this:
0 1 |g�!�2�
1 1 1
2 2 2
3 6 6
4 24 24
5 120 120
6 720 720
7 5040 5040
8 40320 40320
9 362880 362880
10 3628800 3628800
11 39916800 39916800
12 479001600 479001600
13 6227020800 6227020800
14 87178291200 87178291200
15 1307674368000 1307674368000
16 20922789888000 20922789888000
17 355687428096000 355687428096000
18 6402373705728000 6402373705728000
19 121645100408832000 121645100408832000
20 2432902008176640000 2432902008176640000
Line 0 should show 1 in the third column, what happens? It Appears somthing wrong with the malloc.
Thanks!
Not sure that I understand your question.
fact_table = malloc(sizeof(struct fact_entry));
Would only allocate memory for one structure, to have a pointer to a 2d array you'd do
fact_entry **fact_table;
fact_table = malloc(sizeof(struct fact_entry) * RowAmount);
for(int row=0; row < RowAmount; row++)
fact_table[row] = malloc(sizeof(struct fact_entry) * ColAmount);
Now you've allocated memory for a 2d array; every row has columns. And now to access the 2D array you could just do
fact_table[rowIndex][colIndex].myvar
When using Malloc, Realloc, Calloc etc, you've got to keep track of the array size yourself so keep variables for the Rows / Cols. If you want to leave out the columns and only have an array of Rows do the following.
fact_entry *fact_table;
fact_table = malloc(sizeof(struct fact_entry) * RowAmount);
Now you can access the structures by
fact_table[rowIndex].myVar
And don't forget to Free your objects
for(int Row=0; Row < RowAmount; Row++)
free(fact_table[Row]);
free(fact_table);
fact_table = malloc(sizeof(struct fact_entry));
Why? In the first case I'm reserving memory for only one row, true?
Why isn't causing a segmentation fault error?
Correct. But bad code does not imply a crash. You will write on memory that you have not expected to be allocated. But it is your memory! Depending on the implementation malloc might allocate a page size block of memory. This potentially means 4096 bytes. Only if you overwrite this might it crash. Or if you make another allocation which comes from that page might you see problems.
The second, why I can fill in the third column? I can't allocate
memory.. I don't know how I can refer to every row, because I have a
struct with a pointer in a loop... and I don't know how to define the
iterations in the malloc.
Not sure I follow. You can either make a single malloc to allocate all the memory in one go. Then manually loop to fix up the address of str_fact into that block of memory. But that's unnecessarily complicated, although does mean you only have a single alloc. The answer provided by #SuperAgenten Johannes is the correct approach though IMO.
Well I have been studying a little C this winter break and in my adventures I stumbled upon an issue with a Dynamic Array.
It's a fairly simple program really. What I am trying to do is to create an array that holds the numbers of the Fibonacci series. Here is the code:
#include <stdio.h>
#include <stdlib.h>
int dynamic_arry_append(int* arry, int* number, int* size);
int main() {
int i, n, size = 3, *arry = NULL, fibarr[size];
printf("Dynamic array, Fibonacci series. \n");
printf("Capture upto element: ");
scanf("%d", &n);
i = 0;
// passing the first elements
fibarr[0] = 0;
fibarr[1] = 1;
fibarr[2] = 1;
while ( i < n ) {
printf("**%d\n",fibarr[0]);
dynamic_arry_append( arry, &fibarr[0], &size );
fibarr[0] = fibarr[1];
fibarr[1] = fibarr[2];
fibarr[2] = fibarr[1] + fibarr[0];
i++;
}
for ( i = 0 ; i < size ; i++)
printf("Element %d of the array: %d.\n", i, arry[i]);
return 0;
}
int dynamic_arry_append(int* arry, int* number, int* size) {
int i;
int bacon = *size; // first name i thought of
bacon++;
int *new_addr = realloc(arry, bacon * sizeof(int));
if( new_addr != NULL ) {
arry = new_addr;
arry[bacon-1] = *number;
// printf for easier debugging, or so i thought
for ( i = 0 ; i < bacon ; i++ )
printf("%d\t%d\n", i+1, arry[i]);
printf("\n");
*size = bacon;
} else {
printf("Error (re)allocating memory.");
exit (1);
}
return 0;
}
At least in my mind this works. However, in practice I get funny results:
Dynamic array, Fibonacci series.
Capture upto element: 5
**0 // next fibonacci number
1 5256368
2 5246872
3 1176530273
4 0
**1
1 5256368
2 5246872
3 1768053847
4 977484654
5 1
**1
1 5256368
2 5246872
3 1551066476
4 1919117645
5 1718580079
6 1
**2
1 5256368
2 5246872
3 977484645
4 1852397404
5 1937207140
6 1937339228
7 2
**3
1 5256368
2 5246872
3 1551071087
4 1953724755
5 842231141
6 1700943708
7 977484653
8 3
/* Code::Blocks output */
Process returned -1073741819 (0xC0000005) execution time : 17.886 s
Press any key to continue.
I am really baffled by this error, and after searching around I found no solution...Can anyone help? Thank you very much.
#include <stdio.h>
#include <stdlib.h>
int * dynamic_array_append(int * array, int size);
int main() {
int i, n, size=0, *array = NULL;
printf("Dynamic array, Fibonacci series. \n");
printf("Capture upto element: ");
scanf("%d", &n);
for (i=0 ; i<n ; i++)
array = dynamic_array_append(array, i);
for (i=0 ; i<n ; i++)
printf("array[%d] = %d\n", i, array[i]);
return 0;
}
int * dynamic_array_append(int * array, int size)
{
int i;
int n1, n2;
int new_size = size + 1;
int * new_addr = (int *) realloc(array, new_size * (int)sizeof(int));
if (new_addr == NULL) {
printf("ERROR: unable to realloc memory \n");
return NULL;
}
if (size == 0 || size == 1) {
new_addr[size] = size;
return new_addr;
}
n1 = new_addr[size-1];
n2 = new_addr[size];
new_addr[new_size-1] = new_addr[new_size-2] + new_addr[new_size-3];
return new_addr;
}
/*
Output:
Dynamic array, Fibonacci series.
Capture upto element: 10
array[0] = 0
array[1] = 1
array[2] = 1
array[3] = 2
array[4] = 3
array[5] = 5
array[6] = 8
array[7] = 13
array[8] = 21
array[9] = 34
*/
Points to note:
The newly (re)allocated array should be returned back to main and stored in a pointer-to-int (or) pass pointer-to-pointer-to-int and update it accordingly once after reallocing
The fibarr is not needed. It doesn't solve any problem.
You don't have to pass the size and the number. Just send the size and it will pick the n-1 and n-2 to calculate n.
This is considered to be highly inefficient. Because if you know the n then you can allocate memory for n integers in one shot and calculate the fib series.
The problem may be that the arry pointer variable is passed by value to the function dynamic_arry_append. That means, that changes that you make to the arry variable within that function will not be reflected by any variables outside of that function. For example:
int *a = NULL;
someFunc(a);
// a will still be NULL here no matter what someFunc does to it.
You should declare your fibarr as a pointer (so name it differently) not an array. And you should pass to your dynamic_arry_append the address of that pointer, like &fibarr. And you should initialize fibarr in your main with calloc. At last you should dynamically update (and keep, and pass) the size of the allocated array.
You are not returning the new address of the array... and you are reading/writing not your memory. Run the program with all error messages under debugger and you'll see the problem is in this line:
dynamic_arry_append( arry, &fibarr[0], &size );