integer array to char pointer string - c

I'm trying to convert int array to char pointer string (array values converted to hex).I'm using codeblocks editor.
so,
int arr[4] = {30, 40, 15, 205};
should be converted to
char *str = "1e280fcd";
I have written the following program to do so:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *cur_str, *prev_str;
char *comp_str, *comp_str_copy;
int arr[] = {30,40,15,205}, i, j, arr_length;
arr_length = (sizeof(arr)/sizeof(arr[0]));
prev_str = malloc(sizeof(0));
cur_str = malloc(sizeof(0));
comp_str = malloc(sizeof(0));
for(i=0;i<arr_length;i++)
{
cur_str = malloc(2);
sprintf(cur_str,"%02x",arr[i]);
comp_str = malloc(sizeof(cur_str)+sizeof(prev_str));
sprintf(comp_str,"%s%s",prev_str,cur_str);
printf("%s\n",comp_str);
free(prev_str);
prev_str = malloc(sizeof(comp_str));
sprintf(prev_str,"%s",comp_str);
if(i==(arr_length-1)){
comp_str_copy = malloc(sizeof(comp_str));
sprintf(comp_str_copy,"%s",comp_str);
}
free(comp_str);
free(cur_str);
}
printf("%s %d\n",comp_str_copy,strlen(comp_str_copy));
return 0;
}
This program's output is either
segmentation fault or
A string with garbage value in the initial locations
I've run the same program on different online compilers. They all give the correct string as output.Is the editor i'm using an issue or my memory management methods?

In
cur_str = malloc(2);
sprintf(cur_str,"%02x",arr[i]);
the sprintf write 3 characters including the final null character, while you allocated only 2
In
comp_str = malloc(sizeof(cur_str)+sizeof(prev_str));
the allocate length is not the right one because the size_of do not return what you expect, must be
comp_str = malloc(strlen(cur_str)+strlen(prev_str)+1);
but of course that supposes prev_str is also a correct string at the beginning, and this is not the case
These two malloc will produce memory leaks because there are not free (nor used)
cur_str = malloc(sizeof(0));
comp_str = malloc(sizeof(0));
Why do you not use realloc to increase the size of prev_str ?
Note the final needed size is easy to know : sizeof(arr)/sizeof(arr[0]) * 2 + 1 if numbers a limited to 255 (2 digits in hexa)
A proposal (without supposing all numbers < 256) :
#include <string.h>
#include <stdlib.h>
int main()
{
int arr[] = {30,40,15,205};
size_t arr_length = sizeof(arr)/sizeof(arr[0]);
size_t i;
size_t sz = 0;
char * r = malloc(0);
for (i=0; i!= arr_length; ++i)
{
char s[20];
int l = sprintf(s, "%02x",arr[i]);
r = realloc(r, sz + l + 1);
strcpy(r + sz, s);
sz += l;
}
printf("%s %d\n", r, sz);
free(r);
return 0;
}
Compilation and xecution :
pi#raspberrypi:/tmp $ gcc -g -pedantic -Wextra a.c
pi#raspberrypi:/tmp $ ./a.out
1e280fcd 8
Execution under valgrind
pi#raspberrypi:/tmp $ valgrind ./a.out
==2985== Memcheck, a memory error detector
==2985== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2985== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2985== Command: ./a.out
==2985==
1e280fcd 8
==2985==
==2985== HEAP SUMMARY:
==2985== in use at exit: 0 bytes in 0 blocks
==2985== total heap usage: 6 allocs, 6 frees, 1,048 bytes allocated
==2985==
==2985== All heap blocks were freed -- no leaks are possible
==2985==
==2985== For counts of detected and suppressed errors, rerun with: -v
==2985== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

That was a lot of dynamic memory allocation for a simple task. If the array and string will remain "small" then use the stack to your advantage:
#include <assert.h>
#include <stdio.h>
int main() {
int const arr[] = {30, 40, 15, 205};
int const arr_length = sizeof(arr) / sizeof(arr[0]);
char str[2 * arr_length + 1];
int len = 0;
for (int i = 0; i < arr_length; i++) {
len += sprintf(&str[len], "%02x", arr[i]);
}
assert(len == 2 * arr_length);
printf("%s %d\n", str, len);
return 0;
}
But if you truly need a dynamic string, i.e.,char *str just modified char str[2 * arr_length + 1]; to
char *str = malloc(2 * arr_length + 1);
and add free(str);
NB: All this assumes that you integer array values are less than 256.

the following proposed code:
eliminates the unneeded code logic
eliminates the unneeded variables
eliminates the unneeded use of dynamic memory
cleanly compiles
does NOT seg fault
performs the desired functionality
note that strlen() returns a size_t, not a int
note that sizeof() returns a size_t not a int
multiplies the length of the array arr[] by 2 to calculate the number of characters needed to display the converted array
adds 1 to the calculated length to allow for the trailing NUL byte
lists the variables in the necessary order so specific parameters are always available when needed
And now, the proposed code:
#include <stdio.h>
#include <string.h>
int main( void )
{
int arr[] = {30,40,15,205};
char comp_str[ sizeof( arr )*2 +1 ] = {'\0'};
size_t arr_length = (sizeof(arr)/sizeof(arr[0]));
for( size_t i=0; i<arr_length; i++ )
{
sprintf( comp_str,"%s%02x", comp_str, arr[i] );
printf("%s\n",comp_str);
}
}
A run of the proposed code results in:
1e
1e28
1e280f
1e280fcd

Related

No access to dynamically allocated array of 2 dimensions [duplicate]

This question already has an answer here:
Dynamic memory access only works inside function
(1 answer)
Closed 3 years ago.
I'm experimenting with the dynamic memory allocation of variable sized arrays. The function "ft_ultimate_range" seems to work, however, a problem arises when I try to access and print the values of each array's array. It signals either segmentation fault: 11, when compiled with GCC, or "subscripted value is neither array nor pointer nor vector" with [http://pythontutor.com/c][1]. I understand that this has to do with the use- or abuse of pointers... ehm
// allocate a grid of [n][n] with numbers ranging max-min
int *ft_ultimate_range(int **range, int min, int max)
{
int len, *ptr;
int count = min;
len = max - min;
ptr = range;
// allocate memory **arr
range = malloc(len * sizeof * range);
for(int i = 0; i < len; i++) {
range[i] = malloc(len * sizeof * ptr);
}
// assign values to allocated memory location
for(int i = 0; i < len; i++) {
for(int j = 0; j < len; j++) {
range[i][j] = count++;
}
count = min;
}
// free memory **range
for(int i = 0; i < len; i++) {
free(range[i]);
}
free(range);
return ptr;
}
int main()
{
int n;
n = 6 - 3;
int **ptr, *arr;
arr = ft_ultimate_range(ptr, 3, 6);
// print
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
printf("%d", ptr[i][j]);
}
}
return 0;
}
...a little pointer in the right direction would be very much appreciated.
Well, it obvious you are quite lost regarding how to return an allocated grid (pointer-to-pointer-to-int) from ft_ultimate_range() to main().
To begin, you do not need to pass range as a parameter to ft_ultimate_range(). Instead, make the return type int ** and declare int **range within ft_ultimate_range() and then allocate len pointers, and then allocate len integers per-pointer, assign the values and then return range and assign it to arr in main(), e.g.
#include <stdio.h>
#include <stdlib.h>
/* allocate a grid of [n][n] with numbers ranging max-min */
int **ft_ultimate_range (int min, int max)
{
int len = max - min,
**range = NULL,
count = min;
/* allocate len pointers */
range = malloc (len * sizeof * range);
if (!range) { /* validate EVERY allocation */
perror ("malloc-range");
return NULL;
}
/* allocate len int per-pointer */
for (int i = 0; i < len; i++) {
range[i] = malloc (len * sizeof *range[i]);
if (!range[i]) { /* validate alloation */
perror ("malloc-range[i]");
while (i--) /* free previously allocated rows */
free (range[i]); /* free pointers */
free (range);
return NULL;
}
}
/* assign values to allocated memory location */
for(int i = 0; i < len; i++) {
for(int j = 0; j < len; j++) {
range[i][j] = count++;
}
count = min;
}
return range;
}
(note: you MUST VALIDATE EVERY ALLOCATION...)
In main(), you don't need ptr, all you need is the int** pointer you will assign the return from ft_ultimate_range() to, e.g.
int main (void) {
int n = 6 - 3;
int **arr;
arr = ft_ultimate_range (3, 6);
if (!arr) /* validate return */
return 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
printf (" %d", arr[i][j]);
}
putchar ('\n');
free (arr[i]);
}
free (arr);
return 0;
}
(note: similarly, you must validate the return of ft_ultimate_range() before blindly looping through the values (that will not be there if an allocation failed)).
Example Use/Output
$ ./bin/alloc_a_grid
3 4 5
3 4 5
3 4 5
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 insure 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/alloc_a_grid
==29026== Memcheck, a memory error detector
==29026== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==29026== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==29026== Command: ./bin/alloc_a_grid
==29026==
3 4 5
3 4 5
3 4 5
==29026==
==29026== HEAP SUMMARY:
==29026== in use at exit: 0 bytes in 0 blocks
==29026== total heap usage: 4 allocs, 4 frees, 60 bytes allocated
==29026==
==29026== All heap blocks were freed -- no leaks are possible
==29026==
==29026== For counts of detected and suppressed errors, rerun with: -v
==29026== 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.
Here:
int **ptr, *arr;
arr = ft_ultimate_range(ptr, 3, 6);
ptr is NULL / uninitialised now. You cant allocate of this. malloc must be before call a function ft_ultimate_range. Here: printf("%d", ptr[i][j]); is NULL[i][j].
And you free **ptr in function ft_ultimate_range.
Hope this help.
int **ptr, *arr;
ptr is uninitialised at this point. It's value is indeterminate.
arr = ft_ultimate_range(ptr, 3, 6);
Passing an uninitialised value to a function is always wrong. If you hope the function will initialise it, you are mistaken. Read on pass by value.
ptr = range;
This assignment is wrong. You should have received a compiler warning about it. If you did not, upgrade your compiler ASAP. Never ignore warnings. Toying with a program that compiles with warnings is a waste of time.
for(int i = 0; i < len; i++) {
free(range[i]);
}
free(range);
At this point, every pointer in the program is invalid. Dereferencing them is undefined behaviour.
It isn't at all clear what your program is supposed to return. You are not using the return value anyway.
I suggest changing the signature of your function to this:
int** ft_ultimate_range(int min, int max)
Try to fit whatever you are trying to do in this mold.

How to print 2d matrices c

I am trying to simulate matrices using 2d arrays. But I am stuck at a run-time error. I am sure it occurs at printing function,but I couldn't find a solution at all.
obtn_matrix is a function that I use to create a matrix array. I didn't share the filler function which is used to get int values for the elements of the matrix array,so printed values will be whats in the memory. However, the problem is, I can't print the values at all. Program crashes after obtn_matrix.
int main()
{
int**matrix,m,n;
obtn_matrix(matrix,m,n);
prnt_matrix(matrix,m,n);
getch();
}
void prnt_matrix(int** matrix,int m,int n)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
printf("%d ",matrix[i][j]);
}
printf("\n");
}
}
void obtn_matrix(int** matrix,int m,int n)
{
printf("Please enter the column number: ");
fflush(stdin);
scanf("%d",&m);
printf("Please enter the row number: ");
fflush(stdin);
scanf("%d",&n);
matrix=create_matrix(m,n);
}
The expected result is something like below:
4542 64 274 4234
765 53 3523 5345
5145 154 545 545
5435 543 545 14
I will handle the formatting (%4d etc). Kindly thanks in advance.
in obtn_matrix the assignment of matrix, m and n are not visible from main , you need to use pointer to them.
For instance, using array of int * because the dimensions are unknown at compile time:
#include <stdio.h>
#include <stdlib.h>
void prnt_matrix(int ** matrix,int m,int n)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
printf("%d ",matrix[i][j]);
}
printf("\n");
}
}
int ** create_matrix(int m, int n)
{
int ** ma = calloc(m, sizeof(int*));
if (ma != NULL) {
int i, j;
for (i = 0; i != m; ++i) {
if ((ma[i] = malloc(n*sizeof(int))) == NULL)
return NULL;
for (j = 0; j != n; ++j) {
ma[i][j] = i*n + j;
}
}
}
return ma;
}
void obtn_matrix(int *** matrix,int * m,int * n)
{
printf("Please enter the row number: ");
fflush(stdin);
scanf("%d",m);
printf("Please enter the column number: ");
fflush(stdin);
scanf("%d",n);
*matrix=create_matrix(*m,*n);
}
void free_matrix(int ** matrix,int m,int n)
{
for(int i=0;i<m;i++)
{
if (matrix[i] == NULL)
/* matrix creation was aborted */
break;
free(matrix[i]);
}
free(matrix);
}
int main()
{
int ** matrix,m,n;
obtn_matrix(&matrix,&m,&n);
if (matrix != NULL) {
prnt_matrix(matrix,m,n);
free_matrix(matrix,m,n);
}
}
Compilation and execution :
pi#raspberrypi:~ $ gcc -pedantic -Wextra m.c
pi#raspberrypi:~ $ ./a.out
Please enter the row number: 3
Please enter the column number: 2
0 1
2 3
4 5
Execution under valgrind
pi#raspberrypi:~ $ valgrind ./a.out
==10436== Memcheck, a memory error detector
==10436== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10436== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10436== Command: ./a.out
==10436==
Please enter the row number: 3
Please enter the column number: 2
0 1
2 3
4 5
==10436==
==10436== HEAP SUMMARY:
==10436== in use at exit: 0 bytes in 0 blocks
==10436== total heap usage: 6 allocs, 6 frees, 2,084 bytes allocated
==10436==
==10436== All heap blocks were freed -- no leaks are possible
==10436==
==10436== For counts of detected and suppressed errors, rerun with: -v
==10436== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
Note it is also possible to just alloc one array of m*n int but in that case rather than to use m[i][j]you need to do m[i*n+j]
If you haven't fully wrapped your head around the basic problem you are having, the problem is this, C passes parameters to functions by value. What this means is that when a parameter is passed, the function receives a copy of the variable which it is free to change -- but any changes are lost when the function returns.
One caveat to this is when an allocated pointer is passed. While it is still passed by value and the pointer will have its very own and very different address from the original, the memory address it holds as its value will still point to the same address as it does in the caller. This is no different that assigning int a = 5; and then passing a as a parameter, the function receives a copy of the variable, but it still contains 5.
However, if you attempt to allocate or reallocate such that the address of the pointer is changed, then any changes made in the function will be lost on return and not visible in the caller.
How Do You Handle This?
You have two options (1) pass the address of the pointer, so any changes to the address can be assigned to the dereferenced pointer (i.e. the original pointer address), or (2) change the return type from void to the type of pointer that needs to be returned and return the newly allocated/reallocated pointer for assignment in the caller.
For example, in your case, you need not pass matrix as a parameter to obtn_matrix() at all. You can simply use option (2) above and change the return type of obtn_matrix() to int ** and return create_matrix (*m, *n); at the end, e.g.
int **create_matrix (int m, int n)
{
int **matrix = malloc (m * sizeof *matrix);
if (matrix == NULL) {
perror ("malloc-matrix");
return NULL;
}
for (int i = 0; i < m; i++)
/* use calloc to initialize values zero */
if ((matrix[i] = calloc (n, sizeof **matrix)) == NULL) {
perror ("malloc-matrix[n]");
return NULL;
}
return matrix;
}
/* use pointers as parameters so the updated values of m, n are
* available back in the caller after the function returns. return
* int** for assignment back in the caller. Avoids becoming a
* 3-Star Programmer (not a compliment). return NULL on failure.
*/
int **obtn_matrix (int *m, int *n)
{
fputs ("enter number of rows: ", stdout);
if (scanf ("%d", m) != 1) { /* validate ALL user-input */
fputs ("error: invalid number of rows.\n", stderr);
return NULL;
}
fputs ("enter number of cols: ", stdout);
if (scanf ("%d", n) != 1) {
fputs ("error: invalid number of cols.\n", stderr);
return NULL;
}
return create_matrix (*m, *n);
}
Now putting it altogether, and making note that #bruno explains why you must pass the address of m, n (e.g. &m, &n) to obtn_matrix (option (1) above) so the updated values of m & n are available back in main() (the caller here), you could do something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int **create_matrix (int m, int n)
{
int **matrix = malloc (m * sizeof *matrix);
if (matrix == NULL) {
perror ("malloc-matrix");
return NULL;
}
for (int i = 0; i < m; i++)
/* use calloc to initialize values zero */
if ((matrix[i] = calloc (n, sizeof **matrix)) == NULL) {
perror ("malloc-matrix[n]");
return NULL;
}
return matrix;
}
/* use pointers as parameters so the updated values of m, n are
* available back in the caller after the function returns. return
* int** for assignment back in the caller. Avoids becoming a
* 3-Star Programmer (not a compliment). return NULL on failure.
*/
int **obtn_matrix (int *m, int *n)
{
fputs ("enter number of rows: ", stdout);
if (scanf ("%d", m) != 1) { /* validate ALL user-input */
fputs ("error: invalid number of rows.\n", stderr);
return NULL;
}
fputs ("enter number of cols: ", stdout);
if (scanf ("%d", n) != 1) {
fputs ("error: invalid number of cols.\n", stderr);
return NULL;
}
return create_matrix (*m, *n);
}
void prnt_matrix (int **matrix, int m, int n)
{
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
printf (" %4d", matrix[i][j]);
putchar ('\n');
}
}
void free_matrix (int **matrix, int m)
{
for (int i = 0; i < m; i++)
free (matrix[i]); /* free integers */
free (matrix); /* free pointers */
}
int main (void) {
int **matrix, m = 0, n = 0;
if ((matrix = obtn_matrix (&m, &n)) == NULL)
return 1;
prnt_matrix (matrix, m, n);
free_matrix (matrix, m);
return 0;
}
Since you "didn't share the filler function", the code above simply zeros all integer values by allocating the integers for each row with calloc instead of malloc which is a good idea when working with simulated arrays so that if you inadvertently fail to initialize one of the integers, you don't SegFault when you attempt to traverse all elements to, e.g. prnt_matrix, etc...
Example Use/Output
$ ./bin/matrix_cr_obtn
enter number of rows: 5
enter number of cols: 3
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
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 insure 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/matrix_cr_obtn
==10251== Memcheck, a memory error detector
==10251== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10251== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==10251== Command: ./bin/matrix_cr_obtn
==10251==
enter number of rows: 5
enter number of cols: 3
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
==10251==
==10251== HEAP SUMMARY:
==10251== in use at exit: 0 bytes in 0 blocks
==10251== total heap usage: 6 allocs, 6 frees, 100 bytes allocated
==10251==
==10251== All heap blocks were freed -- no leaks are possible
==10251==
==10251== For counts of detected and suppressed errors, rerun with: -v
==10251== 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.

pthread_join() causing seg fault

So I've looked over about every issue i could fine both on stack and many other sources. While i was able to fix some issues and add some extra testing it still hasnt resolved my issue. The program is set up with mergesort.c, which calls the functions, mergesortTest.c, which tests my functions. The serial implementation works just fine. I got past the issue with my initial creates. However, now that im trying to join them I'm getting a seg fault. Ive used both valgrind and gdb to test it and its on my join. Though i cant print out an error message since it causes a seg fault and shuts down my program. Ive made sure to try and allocate proper space. However ill post my code and the output of gdb in hopes someone can help me with this.
**mergesort.c**
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define TRUE 1
#define FALSE 0
#define MAX 100000000
#define MAX_CORE 4
// function prototypes
void serial_mergesort(int A[], int p, int r);
void merge(int A[], int p, int q, int r);
void insertion_sort(int A[], int p, int r);
void *pthread_mergesort(void *arg);
struct mergeS
{
int numElements;
int *A;
int level;
int Max_Level;
};
const int INSERTION_SORT_THRESHOLD = 100; //based on trial and error
/*
* insertion_sort(int A[], int p, int r):
*
* description: Sort the section of the array A[p..r].
*/
void insertion_sort(int A[], int p, int r)
{
int j;
for (j=p+1; j<=r; j++) {
int key = A[j];
int i = j-1;
while ((i > p-1) && (A[i] > key)) {
A[i+1] = A[i];
i--;
}
A[i+1] = key;
}
}
/*
* serial_mergesort(int A[], int p, int r):
*
* description: Sort the section of the array A[p..r].
*/
void serial_mergesort(int A[], int p, int r)
{
if (r-p+1 <= INSERTION_SORT_THRESHOLD) {
insertion_sort(A,p,r);
} else {
int q = (p+r)/2;
serial_mergesort(A, p, q);
serial_mergesort(A, q+1, r);
merge(A, p, q, r);
}
}
/*
* pthread_mergesort(void *arg)
*
* description:Sorts based off levels
*
*/
void *pthread_mergesort(void *arg)
{
struct mergeS *threader = (struct mergeS*) arg;
int i = 0;
int flag = 0;
int level = (threader)->level;
printf("level: %d\n",level);
int numElements = threader->numElements;
int Max_Level = threader->Max_Level;
int *A = threader->A;
if(Max_Level == 1)
{
serial_mergesort(A,1,numElements + 1);
return NULL;
}
int low = level * (numElements/Max_Level) + 1;
int high =((level + 1) * ((numElements/Max_Level)));
pthread_t *tids = (pthread_t*) malloc(sizeof(pthread_t) * 2);
struct mergeS *merger = (struct mergeS*) malloc(sizeof(struct mergeS) * 2);
int error = 0;
if(level < Max_Level - 1)
{
for(i = 0;i < 2; i ++)
{
printf("for loop\n");
merger[i].numElements = numElements/(i + 1);
merger[i].level = threader->level + 1;
merger[i].Max_Level = threader->Max_Level;
merger[i].A = threader->A;
if((error = pthread_create(&tids[i],NULL,pthread_mergesort,(void*)&merger[i])) == 0)
{
printf("thread failed\n");
flag = 1;
}
}
printf("error: %d\n",error);
}
serial_mergesort(A,low,high);
int j = 0;
if(flag == 0)
{
for(j = 0;j < 2; j++)
{
printf("for level: %d\n",threader->level);
printf("join = %d\n", j);
if((error = pthread_join(tids[j],NULL)) != 0)
{
printf("error: %d\n",error);
}
}
}
merge(A,low,(high/2) + 1,high);
free(merger);
free (tids);
return NULL;
}
/*
* merge(int A[], int p, int q, int r):
*
* description: Merge two sorted sequences A[p..q] and A[q+1..r]
* and place merged output back in array A. Uses extra
* space proportional to A[p..r].
*/
void merge(int A[], int p, int q, int r)
{
int *B = (int *) malloc(sizeof(int) * (r-p+1));
int i = p;
int j = q+1;
int k = 0;
int l;
// as long as both lists have unexamined elements
// this loop keeps executing.
while ((i <= q) && (j <= r)) {
if (A[i] < A[j]) {
B[k] = A[i];
i++;
} else {
B[k] = A[j];
j++;
}
k++;
}
// now only at most one list has unprocessed elements.
if (i <= q) {
// copy remaining elements from the first list
for (l=i; l<=q; l++) {
B[k] = A[l];
k++;
}
} else {
// copy remaining elements from the second list
for (l=j; l<=r; l++) {
B[k] = A[l];
k++;
}
}
// copy merged output from array B back to array A
k=0;
for (l=p; l<=r; l++) {
A[l] = B[k];
k++;
}
free(B);
}
end of file
**mergesortTest.c**
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_THREAD 4
#define TRUE 1
#define FALSE 0
// function prototypes
int check_if_sorted(int A[], int n);
void generate_random_array(int A[], int n, int seed);
void serial_mergesort(int A[], int p, int r);
void *pthread_mergesort(void *arg);
void merge(int A[], int p, int q, int r);
void insertion_sort(int A[], int p, int r);
double getMilliSeconds();
// Struct
struct mergeS
{
int numElements;
int *A;
int level;
int Max_Level;
};
/*
* generate_random_array(int A[], int n, int seed):
*
* description: Generate random integers in the range [0,RANGE]
* and store in A[1..n]
*/
#define RANGE 1000000
void generate_random_array(int A[], int n, int seed)
{
int i;
srandom(seed);
for (i=1; i<=n; i++){
A[i] = random()%RANGE;
}
}
/*
* check_if_sorted(int A[], int n):
*
* description: returns TRUE if A[1..n] are sorted in nondecreasing order
* otherwise returns FALSE
*/
int check_if_sorted(int A[], int n)
{
int i=0;
for (i=1; i<n; i++) {
if (A[i] > A[i+1]) {
printf("%d > %d\n",A[i],A[i+1]);
printf("i: %d\n",i);
return FALSE;
}
}
return TRUE;
}
int main(int argc, char **argv) {
printf("argc = %d\n",argc);
int n;
int Max_Level = 4;
int flag = 1;
int seed;
if (argc == 1) { // there must be at least one command-line argument
printf("Default: Input Size = 100000000 levels: 4\n");
printf("Usage: executable input size number of levels\n");
n = 100000000;
seed = 4;
flag = 0;
}
if (argc == 2 && flag == 1) {
printf("Default: Threads: 4\n");
printf("Usage: executable input size number of levels\n");
n = atoi(argv[1]);
Max_Level = 4;
seed = 4;
}
if(argc == 3)
{
n = atoi(argv[1]);
Max_Level = atoi(argv[2]);
seed = Max_Level;
}
if(Max_Level > 15)
{
printf("To many levels. Setting to 4\n");
Max_Level = 4;
seed = Max_Level;
}
int *A = (int *) malloc(sizeof(int) * (n+1)); // n+1 since we are using A[1]..A[n]
// generate random input
generate_random_array(A,n,seed);
double start_time;
double sorting_time;
// sort the input (and time it)
start_time = getMilliSeconds();
serial_mergesort(A,1,n);
sorting_time = getMilliSeconds() - start_time;
////////////////////////////////////////////////////////////////////////////////////////////////////// Start of parallel //////////////////////////////////////////////////////////////////////////////////////////////////////
int *B = (int *) malloc(sizeof(int) * (n+1)); // n+1 since we are using A[1]..A[n]
//int i;
double p_start_time;
double p_sorting_time;
struct mergeS *threader = (struct mergeS*) malloc(sizeof(struct mergeS));
generate_random_array(B,n,seed);
// sort the input with threads (and time it)
p_start_time = getMilliSeconds();
threader[0].numElements = n;
threader[0].level = 0;
threader[0].Max_Level = Max_Level;
threader[0].A = B;
pthread_mergesort(threader);
printf("sorted\n");
/*for(i = 0;i < n + 1;i = i + 1)
{
printf("B[%d]: %d\n",i,B[i]);
}
printf("B:[%d] = %d\n",999,B[999]);
*/
p_sorting_time = getMilliSeconds() - p_start_time;
// print results if correctly sorted otherwise cry foul and exit
if (check_if_sorted(A,n)) {
printf("Serial: Sorting %d elements took %4.2lf seconds.\n", n, sorting_time/1000.0);
} else {
printf("%s: sorting failed!!!!\n", argv[0]);
exit(EXIT_FAILURE);
}
if (check_if_sorted(B,n)) {
printf("Threaded: Sorting %d elements took %4.2lf seconds.\n", n, p_sorting_time/1000.0);
} else {
printf("%s: parallel sorting failed!!!!\n", argv[0]);
exit(EXIT_FAILURE);
}
free(threader);
free(A);
free(B);
exit(EXIT_SUCCESS);
}
end of file
**GBD error report and code output**
[rutgerluther#onyxnode72 multi-threaded]$ valgrind --leak-check=yes ./mergesort 1000 2
==5636== Memcheck, a memory error detector
==5636== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5636== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5636== Command: ./mergesort 1000 2
==5636==
argc = 3
level: 0
for loop
thread failed
for loop
thread failed
error: 0
sorted
Serial: Sorting 1000 elements took 0.00 seconds.
993090 > 163007
i: 500
./mergesort: parallel sorting failed!!!!
==5636==
==5636== HEAP SUMMARY:
==5636== in use at exit: 9,152 bytes in 5 blocks
==5636== total heap usage: 30 allocs, 25 frees, 33,216 bytes allocated
==5636==
==5636== 1,120 bytes in 2 blocks are possibly lost in loss record 2 of 4
==5636== at 0x4C2B9B5: calloc (vg_replace_malloc.c:711)
==5636== by 0x40128C4: _dl_allocate_tls (in /usr/lib64/ld-2.17.so)
==5636== by 0x4E3E7FB: pthread_create##GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
==5636== by 0x400E88: pthread_mergesort (mergesort.c:114)
==5636== by 0x400B00: main (mergesortTest.c:145)
==5636==
==5636== LEAK SUMMARY:
==5636== definitely lost: 0 bytes in 0 blocks
==5636== indirectly lost: 0 bytes in 0 blocks
==5636== possibly lost: 1,120 bytes in 2 blocks
==5636== still reachable: 8,032 bytes in 3 blocks
==5636== suppressed: 0 bytes in 0 blocks
==5636== Reachable blocks (those to which a pointer was found) are not shown.
==5636== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==5636==
==5636== For counts of detected and suppressed errors, rerun with: -v
==5636== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
[rutgerluther#onyxnode72 multi-threaded]$ gdb ./mergesort
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-110.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/RutgerLuther/RutgerLuther#u.boisestate.edu/backpack/CS453-1-f18/p2/multi-threaded/mergesort...done.
(gdb) b 130
Breakpoint 1 at 0x400abd: file mergesortTest.c, line 130.
(gdb) r 1000 2
Starting program: /home/RutgerLuther/RutgerLuther#u.boisestate.edu/backpack/CS453-1-f18/p2/multi-threaded/./mergesort 1000 2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
argc = 3
Breakpoint 1, main (argc=<optimized out>, argv=0x7fffffffcf98) at mergesortTest.c:135
135 struct mergeS *threader = (struct mergeS*) malloc(sizeof(struct mergeS));
Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64
(gdb) n
137 generate_random_array(B,n,seed);
(gdb)
140 p_start_time = getMilliSeconds();
(gdb)
141 threader[0].numElements = n;
(gdb)
142 threader[0].level = 0;
(gdb)
143 threader[0].Max_Level = Max_Level;
(gdb)
144 threader[0].A = B;
(gdb)
145 pthread_mergesort(threader);
(gdb)
level: 0
for loop
[New Thread 0x7ffff77f1700 (LWP 5892)]
thread failed
for loop
level: 1
for level: 1
join = 0
[New Thread 0x7ffff6ff0700 (LWP 5893)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff77f1700 (LWP 5892)]
0x00007ffff7bc7f01 in pthread_join () from /lib64/libpthread.so.0
(gdb)
end of file
**Valgrind report**
[rutgerluther#onyxnode72 multi-threaded]$ valgrind --leak-check=yes ./mergesort 1000 2
==5636== Memcheck, a memory error detector
==5636== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5636== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5636== Command: ./mergesort 1000 2
==5636==
argc = 3
level: 0
for loop
thread failed
for loop
thread failed
error: 0
sorted
Serial: Sorting 1000 elements took 0.00 seconds.
993090 > 163007
i: 500
./mergesort: parallel sorting failed!!!!
==5636==
==5636== HEAP SUMMARY:
==5636== in use at exit: 9,152 bytes in 5 blocks
==5636== total heap usage: 30 allocs, 25 frees, 33,216 bytes allocated
==5636==
==5636== 1,120 bytes in 2 blocks are possibly lost in loss record 2 of 4
==5636== at 0x4C2B9B5: calloc (vg_replace_malloc.c:711)
==5636== by 0x40128C4: _dl_allocate_tls (in /usr/lib64/ld-2.17.so)
==5636== by 0x4E3E7FB: pthread_create##GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
==5636== by 0x400E88: pthread_mergesort (mergesort.c:114)
==5636== by 0x400B00: main (mergesortTest.c:145)
==5636==
==5636== LEAK SUMMARY:
==5636== definitely lost: 0 bytes in 0 blocks
==5636== indirectly lost: 0 bytes in 0 blocks
==5636== possibly lost: 1,120 bytes in 2 blocks
==5636== still reachable: 8,032 bytes in 3 blocks
==5636== suppressed: 0 bytes in 0 blocks
==5636== Reachable blocks (those to which a pointer was found) are not shown.
==5636== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==5636==
==5636== For counts of detected and suppressed errors, rerun with: -v
==5636== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
[rutgerluther#onyxnode72 multi-threaded]$
end of file
Im running this giving it only a 1000 elements and only using 2 threads. Though the issue still happens with any threads more than 1.
Ive read the man pages and looked at other exmaples and previous cases where i used this and class mates did. But i still cant figure it out.
Any help is appreciated.
If changed some things and pthread is creating correctly. This is stepping into the function. I dont know what the value of tids[0] should be. But the elements in the array are random numbers.
**mergesort.c function call on tids**
level: 1
116 if((error = pthread_create(&tids[i],NULL,pthread_mergesort,(void*)&merger[i])) != 0)
(gdb) info tids
Undefined info command: "tids". Try "help info".
(gdb) print tids[0]
$2 = 140737345689344
(gdb) print &tids
Address requested for identifier "tids" which is in register $r14
(gdb) print *tids
$3 = 140737345689344
(gdb) n
thread failed
for level: 1
join = 0
117 {
(gdb) print tids
$4 = (pthread_t *) 0x604f90
(gdb) print tids[0]
$5 = 140737345689344
(gdb)
The tids array contains uninitialized data if the branch if(level < Max_Level - 1) is not taken. You need to call pthread_join only if you called pthread_create successfully.

How to transfer elements from a void pointer array allocated in the stack to the heap?

Say I have an array of void pointers
void* arr[10];
and I want to transfer that to the heap. I assume I would just allocate a new pointer array using malloc and then start copying individual elements no?
void stackTheap(void** arr)
{
void** arr_new = malloc(20*sizeof(void*));
for(int i = 0; i < 10; i++)
{
arr_new[i] = arr[i];
}
}
But for some reason as soon as my program reaches the for loop the original arr* points to zero.
Heres my actual code just in case its some stupid syntax error:
void regularTodynamic(hybrid_array* arr)
{
if(arr->dynamic_mode_flag == 0)
{
void** new_array = malloc(sizeof(void*)*40);
for(int i = 0; i < arr->elem_count; i++)
{
new_array[i] = arr->content[i];
}
arr->total_size = 30;
arr->dynamic_mode_flag = 1;
}
}
From the code, I guess only a partial answer is possible -- referring to your first snippet here only:
void* arr[10];
This is an array of 10 void pointers -- so far so good, but this:
void stackTheap(void* arr) { ...
will just take a single void pointer. It should probably be
void stackTheap(void** arr) { ...
Then for your copy, you allocate like this:
void** arr_new = malloc(20);
How do you know you need these 20 bytes? In fact, on a common 32bit architecture, you would already need 40. If you're really working with fixed array sizes, this should be:
void** arr_new = malloc(10 * sizeof(void *));
The sizeof(void *) will be e.g. 4 on x86, 8 on amd64, etc ...
This is still very limited, suggest to give your function a size_t argument for passing the actual array length:
void stackTheap(void** arr, size_t nelem)
{
void** arr_new = malloc(nelem * sizeof(void *));
...
All in all, it remains a mystery to me what you actually try to achieve ...
If I understand that you want to handle changing the storage for an array of pointers currently with static storage (on the stack in common terms) to a newly allocated block of memory, then you need to consider whether you simply want to change the storage of the pointers (referred to at times as a shallow copy) or whether you want to change the storage of both the pointers as well as the data pointed to (a deep copy).
While this is impossible to accomplish without passing more information to your stackTheap function, if you provide it with the number of pointers you are dealing with, and the size of the data type pointed to, you can accomplish either a shallow or deep copy depending on what you pass to stackTheap.
The following is just one example to approach a function that will either perform a shallow copy (if dsz is 0), or a deep copy if dsz is passed a value. (there are many ways to pass various flags and parameters to accomplish this, this is just one approach)
Below, the example shows a shallow copy of parr (pointer array) to narr (new array). It then provides an example of a deep copy from parr to narr2 with intermediate type pruning to char using the same function. I'm not certain this is exactly what you are looking for, but if so and you have questions, just let me know:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXI 10
/* void copy array 'arr' of type 'sz' to 'arr_new'. if 'arr' is a
* pointer to an array of pointers to type 'dsz', a deep copy is
* required to copy contents pointed to by each of the array of
* pointers to a newly allocate block of memory.
* For a shallow copy, 'dsz = 0'.
*/
void *stackTheap (void *arr, size_t n, size_t sz, size_t dsz)
{
if (!arr) return NULL;
void* arr_new = malloc (n * sz);
memcpy (arr_new, arr, n * sz);
if (dsz) {
size_t i;
for (i = 0; i < n; i++) {
char **a = (char **)arr;
char **n = (char **)arr_new;
n[i] = malloc (dsz);
memcpy (n[i], a[i], dsz);
}
}
return arr_new;
}
int main (void) {
void *parr[MAXI] = {NULL}; /* void pointer array */
void **narr = {NULL}; /* new array (shallow copy) */
void **narr2 = {NULL}; /* new array (deep copy) */
int arr[MAXI] = {10,20,30,40,50,60,70,80,90,100}; /* array */
int i;
/* assigned pointers */
for (i = 0; i < MAXI; i++)
parr[i] = &arr[i];
/* print addressess of pointers and data on stack */
printf ("\n pointers stored on the stack\n");
for (i = 0; i < MAXI; i++)
printf (" parr[%2d] : %3d %p -> %p\n", i, *(int *)parr[i],
&parr[i], parr[i]);
/* shallow copy 'parr' to 'narr' */
narr = stackTheap (parr, MAXI, sizeof (int*), 0);
/* print address of pointers on heap data on stack */
printf ("\n pointers allocated on the heap\n"
" (pointing to original values on stack)\n");
for (i = 0; i < MAXI; i++)
printf (" narr[%2d] : %3d %p -> %p\n", i, *(int *)narr[i],
&narr[i], narr[i]);
/* deep copy 'parr' to 'narr2' */
narr2 = stackTheap (parr, MAXI, sizeof (int*), sizeof (int));
/* print addresses of pointers and data on heap */
printf ("\n pointers and data allocated on the heap\n");
for (i = 0; i < MAXI; i++)
printf (" narr2[%2d] : %3d %p -> %p\n", i, *(int *)narr2[i],
&narr2[i], narr2[i]);
/* free memory here */
free (narr);
for (i = 0; i < MAXI; i++)
free (narr2[i]);
free (narr2);
return 0;
}
Output
$ ./bin/void_pcpy
pointers stored on the stack
parr[ 0] : 10 0x7fff101e1a90 -> 0x7fff101e1a60
parr[ 1] : 20 0x7fff101e1a98 -> 0x7fff101e1a64
parr[ 2] : 30 0x7fff101e1aa0 -> 0x7fff101e1a68
parr[ 3] : 40 0x7fff101e1aa8 -> 0x7fff101e1a6c
parr[ 4] : 50 0x7fff101e1ab0 -> 0x7fff101e1a70
parr[ 5] : 60 0x7fff101e1ab8 -> 0x7fff101e1a74
parr[ 6] : 70 0x7fff101e1ac0 -> 0x7fff101e1a78
parr[ 7] : 80 0x7fff101e1ac8 -> 0x7fff101e1a7c
parr[ 8] : 90 0x7fff101e1ad0 -> 0x7fff101e1a80
parr[ 9] : 100 0x7fff101e1ad8 -> 0x7fff101e1a84
pointers allocated on the heap
(pointing to original values on stack)
narr[ 0] : 10 0x1e00010 -> 0x7fff101e1a60
narr[ 1] : 20 0x1e00018 -> 0x7fff101e1a64
narr[ 2] : 30 0x1e00020 -> 0x7fff101e1a68
narr[ 3] : 40 0x1e00028 -> 0x7fff101e1a6c
narr[ 4] : 50 0x1e00030 -> 0x7fff101e1a70
narr[ 5] : 60 0x1e00038 -> 0x7fff101e1a74
narr[ 6] : 70 0x1e00040 -> 0x7fff101e1a78
narr[ 7] : 80 0x1e00048 -> 0x7fff101e1a7c
narr[ 8] : 90 0x1e00050 -> 0x7fff101e1a80
narr[ 9] : 100 0x1e00058 -> 0x7fff101e1a84
pointers and data allocated on the heap
narr2[ 0] : 10 0x1e00070 -> 0x1e000d0
narr2[ 1] : 20 0x1e00078 -> 0x1e000f0
narr2[ 2] : 30 0x1e00080 -> 0x1e00110
narr2[ 3] : 40 0x1e00088 -> 0x1e00130
narr2[ 4] : 50 0x1e00090 -> 0x1e00150
narr2[ 5] : 60 0x1e00098 -> 0x1e00170
narr2[ 6] : 70 0x1e000a0 -> 0x1e00190
narr2[ 7] : 80 0x1e000a8 -> 0x1e001b0
narr2[ 8] : 90 0x1e000b0 -> 0x1e001d0
narr2[ 9] : 100 0x1e000b8 -> 0x1e001f0
Memory Check
$ valgrind ./bin/void_pcpy
==18688== Memcheck, a memory error detector
==18688== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==18688== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==18688== Command: ./bin/void_pcpy
==18688==
<snip>
==18688==
==18688== HEAP SUMMARY:
==18688== in use at exit: 0 bytes in 0 blocks
==18688== total heap usage: 12 allocs, 12 frees, 200 bytes allocated
==18688==
==18688== All heap blocks were freed -- no leaks are possible
==18688==
==18688== For counts of detected and suppressed errors, rerun with: -v
==18688== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

Converting a 2D array into a dynamic array causes core dump

I have a perfectly working code with 2D array of a float variable, vxy, in C language. The size of row (rrow) is being calculated inside the code - column (ccol) size is already known. So I tried converting using code fragments in this forum and both causes segmentation fault. The two codes are i) Bryan's method from how to allocate memory dynamically for a two dimensional array and ii) Using pointer to a pointer method from http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/. I chose these methods as the code is already functional with a 2D array so the rest of the code will survive this change.
static float vxy[5000][ccol] ;
vxy[r][c] = ...
The original 2D declaration and usage is above:
#include <stdlib.h>
int main(void)
{
int num_row = 3, num_col = 2, r;
int ** A;
A = malloc(num_row*(sizeof(*A)+num_col*sizeof(**A)));
for (r = 0; r < num_row; r++)
{
A[r] = (int*)(A+num_row)+r*num_col;
}
/* Accessing element at row r and column c is through:
*
* A[r][c].
*/
free(A);
return 0;
}
My implementation based on the above is:
int r;
float ** vxy;
vxy = malloc(rrow*(sizeof(*vxy)+ ccol*sizeof(**vxy)));
for (r = 0; r < rrow; r++) {
vxy[r] = (float*)(vxy + rrow) + r*ccol;
}
The second method is:
float **vxy = (float **)malloc(rrow * sizeof(float *));
for (i=0; i<rrow; i++)
vxy[i] = (float *)malloc(ccol * sizeof(float));
I updated the above 2nd method with the following - I got "Program received signal SIGSEGV, Segmentation fault" on the line of vxy[i] = malloc(ccol * sizeof(float));
float **vxy = malloc(rrow * sizeof(float *));
if (vxy = NULL) {
printf ("Memory allocation error.\n");
// return NULL;
}
for (i = 0; i < rrow; i++)
vxy[i] = malloc(ccol * sizeof(float));
What seems to going wrong with my implementation?
Update: I updated the full code from the source for the method one. I also want to know how to free the allocation and address failed malloc situations.
I'm sorry you are having difficulty with your 2D allocation, it really isn't too difficult. To dynamically allocate and access your elements with array[x][y] notation, you need to allocate x pointers to an array of float's (your rows), then allocate an y arrays of float's (your elements/columns) for each row. (no different than allocating an array of pointers to strings to hold lines of text)
An example of a simple allocation/initialization function with calloc (with m rows and n columns) shown without error checking on allocation is:
float **mtrx_calloc (size_t m, size_t n)
{
register size_t i;
float **array = calloc (m, sizeof *array);
for (i = 0; i < m; i++)
{
array [i] = calloc (n, sizeof **array);
}
return array;
}
To allocate a 3x4 matrix, you would use it like this:
float **matrix = mtrx_calloc (3, 4);
You can then manipulate the matrix as you like accessing all elements with matrix[x][y] notation. Also note the use of size_t instead of int. Your rows and columns and iterator will never be negative, so choosing size_t or unsigned type makes more sense.
Sometimes rather than looking at pieces of code, it is good to have a working example. I put together a short working example to help you along that includes all points we have discussed so far in the comments and above. It includes error checking on memory allocation omitted above. If you have any questions, just drop a comment.
#include <stdio.h>
#include <stdlib.h>
float **mtrx_calloc (size_t m, size_t n); /* initialize elements to 0 */
void mtrx_prn (size_t m, size_t n, float **matrix); /* print matrix with/pad */
void mtrx_free (size_t m, float **matrix); /* free memory allocated */
int main (void)
{
/* allocate the 3x4 matrix */
float **matrix = mtrx_calloc (3, 4);
/* fill with misc values */
register size_t i = 0, j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
matrix [i][j] = (float)(i + j);
}
/* print matrix */
printf ("\nThe dynamically allocated 3x4 matrix is:\n\n");
mtrx_prn (3, 4, matrix);
/* free memory alocated */
mtrx_free (3, matrix);
/* just to make it look pretty */
printf ("\n");
return 0;
}
/* allocate/initialize mxn matrix */
float **mtrx_calloc (size_t m, size_t n)
{
register size_t i;
float **array = calloc (m, sizeof *array);
if (!array) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.\n", __func__);
exit (EXIT_FAILURE);
}
for (i = 0; i < m; i++)
{
array[i] = calloc (n, sizeof **array);
if (!array[i]) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.\n", __func__);
exit (EXIT_FAILURE);
}
}
return array;
}
/* print a (m x n) matrix (check pad alloc) */
void mtrx_prn (size_t m, size_t n, float **matrix)
{
register size_t i, j;
for (i = 0; i < m; i++)
{
char *pad = "[ ";
for (j = 0; j < n; j++)
{
printf ("%s%6.3f", pad, matrix [i][j]);
pad = ", ";
}
printf ("%s", " ]\n");
}
}
void mtrx_free (size_t m, float **matrix)
{
register size_t i;
for (i = 0; i < m; i++)
{
free (matrix [i]);
}
free (matrix);
}
Output
(note: the fill with misc values equation was changed to prevent overflow on entry of large m x n, so output values will differ from below)
$ ./bin/mtrx_dyn_example
The dynamically allocated 3x4 matrix is:
[ 1.900, 2.800, 3.700, 4.600 ]
[ 2.800, 3.700, 4.600, 5.500 ]
[ 3.700, 4.600, 5.500, 6.400 ]
Leak Check with valgrind
When you are creating/allocating blocks of memory dynamically, you are responsible to tracking what you have allocated, preserving the starting address for the block of memory, and freeing the block of memory when you no longer need it. A great tool to help you check your memory use is a memory checker such as valgrind. (similar tools are available for all platforms). Simple to use, just valgrind ./progname. It will confirm for you whether any blocks remain unfreed and whether there are any access errors regarding your allocated blocks:
$ valgrind ./bin/mtrx_dyn_example
==15800== Memcheck, a memory error detector
==15800== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==15800== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==15800== Command: ./bin/mtrx_dyn_example
==15800==
The dynamically allocated 3x4 matrix is:
[ 1.900, 2.800, 3.700, 4.600 ]
[ 2.800, 3.700, 4.600, 5.500 ]
[ 3.700, 4.600, 5.500, 6.400 ]
==15800==
==15800== HEAP SUMMARY:
==15800== in use at exit: 0 bytes in 0 blocks
==15800== total heap usage: 4 allocs, 4 frees, 72 bytes allocated
==15800==
==15800== All heap blocks were freed -- no leaks are possible
==15800==
==15800== For counts of detected and suppressed errors, rerun with: -v
==15800== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
The problem is with the interplay between pointer to floats and actual floats, as mentioned in referenced answers, try to remove the type-casting and see what you get.
Both methods are valid (but accessed in different ways), there is also a first method which creates a 1-d array which represents a 2d array (thus accessed as a[i+j*r]), while the (first and) second methods actually allocates a 2-d array (accessed as a[i][j]).
try to use calloc as well if this helps, although malloc should be fine
Also try to fix your indices correctly (in the loops) when using either method to make sure you dont access memory out-of-bounds in the allocated array

Resources