I have a struct in my code that gets its value changed even though I don't reference at all. The code is:
layer l = linear(2, 3);
neural_network network = create_network();
add_layer(&network, &l);
printf("Before: %llu\n", network.layers[0].weights.column_size);
matrix i = create_matrix(2, 1);
printf("After: %llu\n", network.layers[0].weights.column_size);
And the output to this code is:
Before: 2
After: 0
This doesn't make sense to me as create_matrix is defined as:
matrix create_matrix(uint64_t row_size, uint64_t column_size) {
matrix mat;
mat.row_size = row_size;
mat.column_size = column_size;
mat.array = malloc(sizeof(double) * mat.row_size * mat.column_size);
return mat;
}
I guessed that malloc was messing up for some reason so I printed the addresses of each one and got this:
Address of network.layers[0].weights.column_size: 0x600000b4c010
Before: 2
Address of mat.array: 0x600000b4c010
After: 0
So C is somehow allocating heap memory that should already be used. I'm not really sure why this is going on as I never freed any of the memory. The relevant structs are defined as:
typedef struct layer {
uint64_t neurons;
matrix weights;
matrix biases;
matrix (*compute_activations)(struct layer *l, matrix *activations);
} layer;
typedef struct {
uint16_t number_of_layers;
layer *layers;
} neural_network;
typedef struct {
uint64_t row_size;
uint64_t column_size;
double *array;
} matrix;
Minimum Reproductible Example:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cblas.h>
#include <string.h>
typedef struct {
uint64_t row_size;
uint64_t column_size;
double *array;
} matrix;
typedef struct layer{
uint64_t neurons;
matrix weights;
matrix biases;
matrix (*compute_activations)(struct layer *l, matrix *activations);
} layer;
typedef struct {
uint16_t number_of_layers;
layer *layers;
} neural_network;
matrix create_matrix(uint64_t row_size, uint64_t column_size) {
matrix mat;
mat.row_size = row_size;
mat.column_size = column_size;
mat.array = malloc(sizeof(double) * mat.row_size * mat.column_size);
return mat;
}
matrix matrix_m_multiply(matrix *A, matrix *B, matrix *C, double alpha, double beta) {
matrix C_copy = create_matrix(C->row_size, C->column_size);
memcpy(C_copy.array, C->array, C->row_size * C->column_size * sizeof(double));
cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
A->row_size, B->column_size, A->column_size, alpha,
A->array, A->column_size, B->array, B->column_size, beta,
C_copy.array, C->column_size);
return C_copy;
}
matrix matrix_v_multiply(matrix *A, matrix *B, matrix *C, double alpha, double beta) {
matrix C_copy = create_matrix(C->row_size, C->column_size);
memcpy(C_copy.array, C->array, C->row_size * C->column_size * sizeof(double));
cblas_dgemv(CblasRowMajor, CblasNoTrans,
A->row_size, A->column_size, alpha,
A->array, A->column_size, B->array, 1, beta,
C_copy.array, 1);
return C_copy;
}
neural_network create_network() {
neural_network network = { .number_of_layers = 0 };
network.layers = malloc(sizeof(layer) * network.number_of_layers);
return network;
}
void add_layer(neural_network *network, layer *l) {
network->layers = realloc(network->layers, ++network->number_of_layers);
network->layers[network->number_of_layers - 1] = *l;
}
matrix forward_pass(neural_network *network, matrix *inputs) {
matrix activations = *inputs;
for (int i = 0; i < network->number_of_layers; i++) {
activations = network->layers[i].compute_activations(&network->layers[i], &activations);
}
return activations;
}
matrix linear_function(layer *linear_layer, matrix *activations) {
return matrix_v_multiply(&linear_layer->weights, activations, &linear_layer->biases, 1.0, 1.0);
}
layer linear(uint64_t in, uint64_t out) {
layer linear_layer;
linear_layer.neurons = out;
linear_layer.weights = create_matrix(out, in); // Don't have to transpose matrix when doing vector product with inputs
linear_layer.biases = create_matrix(out, 1);
linear_layer.compute_activations = linear_function;
return linear_layer;
}
int main(int argc, char *argv[]) {
srand(0);
layer l = linear(2, 3);
neural_network network = create_network();
add_layer(&network, &l);
printf("Before: %llu\n", network.layers[0].weights.column_size);
matrix i = create_matrix(2, 1);
printf("After: %llu\n", network.layers[0].weights.column_size);
matrix output = forward_pass(&network, &i);
return 0;
}
There are at least two problems in your code:
in function create_network(), you allocate 0 bytes with malloc(), which has implementation defined behavior. You might instead initialize the layers member to a null pointer:
neural_network create_network(void) {
neural_network network = { .number_of_layers = 0, .layers = NULL };
return network;
}
the size reallocated by add_layer() is incorrect: you forgot to multiply the new number of elements by the element size. This problem is the likely explanation for your observations. You should write:
void add_layer(neural_network *network, layer *l) {
network->layers = realloc(network->layers,
sizeof(*network->layers) *
(network->number_of_layers + 1));
network->layers[network->number_of_layers++] = *l;
}
you do not check for memory allocation failure anywhere in your code. I would recommend using malloc, calloc, strdup and realloc wrappers to test for unlikely yet possible allocation failure and exit with an informative message.
Related
I am having issues returning a 2D array from a C extension back to Python. When I allocate memory using malloc the returned data is rubbish. When I just initialise an array like sol_matrix[nt][nvar] the returned data is as expected.
#include <Python.h>
#include <numpy/arrayobject.h>
#include <math.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
// function to be solved by Euler solver
double func (double xt, double y){
double y_temp = pow(xt, 2);
y = y_temp;
return y;
}
static PyObject* C_Euler(double h, double xn)
{
double y_temp, dydx; //temps required for solver
double y_sav = 0; //temp required for solver
double xt = 0; //starting value for xt
int nvar = 2; //number of variables (including time)
int nt = xn/h; //timesteps
double y = 0; //y starting value
//double sol_matrix[nt][nvar]; //works fine
double **sol_matrix = malloc(nt * sizeof(double*)); //doesn't work
for (int i=0; i<nt; ++i){
sol_matrix[i] = malloc (nvar * sizeof(double));
}
int i=0;
//solution loop - Euler method.
while (i < nt){
sol_matrix[i][0]=xt;
sol_matrix[i][1]=y_sav;
dydx = func(xt, y);
y_temp = y_sav + h*dydx;
xt = xt+h;
y_sav=y_temp;
i=i+1;
}
npy_intp dims[2];
dims[0] = nt;
dims[1] = 2;
//Create Python object to copy solution array into, get pointer to
//beginning of array, memcpy the data from the C colution matrix
//to the Python object.
PyObject *newarray = PyArray_SimpleNew(2, dims, NPY_DOUBLE);
double *p = (double *) PyArray_DATA(newarray);
memcpy(p, sol_matrix, sizeof(double)*(nt*nvar));
// return array to Python
return newarray;
}
static PyObject* Euler(PyObject* self, PyObject* args)
{
double h, xn;
if (!PyArg_ParseTuple(args, "dd", &h, &xn)){
return NULL;
}
return Py_BuildValue("O", C_Euler(h,xn));
}
Could you provide any guidance on where I am going wrong?
Thank you.
The data in sol_matrix is not in contiguous memory, it's in nt separately allocated arrays. Therefore the line
memcpy(p, sol_matrix, sizeof(double)*(nt*nvar));
is not going to work.
I'm not a big fan of pointer-to-pointer arrays so believe your best option is to allocate sol_matrix as one big chunk:
double *sol_matrix = malloc(nt*nvar * sizeof(double));
This does mean you can't do 2D indexing so will need to do
// OLD: sol_matrix[i][0]=xt;
sol_matrix[i*nvar + 0] = xt;
In contrast
double sol_matrix[nt][nvar]; //works fine
is a single big chunk of memory so the copy works fine.
Allocating memory to matrix struct with some values of [row, column] pair for create_matrix function changes values of layer->values pointer which has no relation with matrix struct being allocated.
Some tested [row, column] values are:
[1, 2]
[2, 2]
gdb output for [2,2] i.e create_matrix(2, 2):
(gdb) print *prev_layer
$1 = {
nodes = 2,
weights = 0xb6438030,
biases = 0xb6438060,
values = 0xb6438080
}
(gdb) n
(before allocation): 0xb6438080
50 weights = create_matrix(2, 2);
(gdb) n
51 if (!weights)
(gdb) print *prev_layer
$2 = {
nodes = 2,
weights = 0xb6438030,
biases = 0xb64380b0, <- this changes
values = 0xb64380c0 <- this changes
}
(gdb)
From above it seems that it assigns last two pointer associated with memory allocation to last two members of the struct. Sometimes even NULL pointer
Program output for [2,2]:
Values of prev_layer->values
(before allocation): 0xb6438080
(after allocation): 0xb64380c0
Code used:
#include <stdlib.h>
#include <stdio.h>
typedef struct matrix {
int rows;
int cols;
double **m;
} matrix;
typedef struct layer {
int nodes;
matrix *weights;
matrix *biases;
matrix *values;
} layer;
matrix *create_matrix(int rows, int cols) {
matrix *ret = malloc(sizeof(matrix));
if (!ret)
return NULL;
double **m = malloc(rows * sizeof(double *));
if (!m)
return NULL;
for (int c = 0; c < rows; c++) {
m[c] = calloc(cols, sizeof(double));
if (!m[c]) {
return NULL;
}
}
ret->rows = rows;
ret->cols = cols;
ret->m = m;
return ret;
}
layer *create_layer(int nodes, const layer *prev_layer) {
matrix *weights, *biases;
/* Just after allocation it changes pointer of
* prev_layer->bias and prev_layer->values
* to last to matrix row allocations
* bug works with values in ordered pair [row, col] => [1,2], [2,2],
* doesn't with when used values like [5,3]
* */
if (prev_layer)
printf("(before allocation): %p\n", prev_layer->values);
weights = create_matrix(1,2);
if (!weights)
return NULL;
if (prev_layer)
printf("(after allocation): %p\n", prev_layer->values);
biases = create_matrix(1, nodes);
if (!biases)
return NULL;
matrix *values = create_matrix(1, nodes);
if (!values)
return NULL;
layer *ret = malloc(sizeof(layer *));
if (!ret)
return NULL;
ret->nodes = nodes;
ret->weights = weights;
ret->biases = biases;
ret->values = values;
return ret;
}
int main() {
int nodes[] = {2, 2};
layer *p1 = create_layer(2, NULL);
layer *p2 = create_layer(2, p1);
return 0;
}
Compiler: clang 9.0.0
The type used to compute the allocation size is incorrect in:
layer *ret = malloc(sizeof(layer *)); // should be sizeof(layer)
You allocate the size of a pointer instead of the size of a structure.
To avoid such silly mistakes, you can use the destination pointer type directly:
layer *ret = malloc(sizeof(*ret));
Alternately, you could use allocation wrapper macros and rely on the compiler to detect mismatched types:
#define ALLOC(t) ((t *)calloc(1, sizeof(t)))
#define ALLOC_ARRAY(t, n) ((t *)calloc(n, sizeof(t)))
layer *ret = ALLOC(layer);
The line with ret's malloc needs to make enough space for a whole layer, however you have asked for enough space for a layer*.
So
layer *ret = malloc(sizeof(layer *));
should be
layer *ret = malloc(sizeof(layer));
I am trying to use LAPACK's dgels_ in C to solve a linear least squares problem. I have to read the matrix A (assumed to have full rank and m>=n) and a vector b from 2 text files. I can easily compile my code, but when i try to run it I get a "segmentation fault 11", but I can't really see why. It is my first time using LAPACK so I don't know if maybe I am using the dgels_ function wrong?? The way I get it the solution x will be overwritten in the vector b? :
lssolve.c:
#include <stdlib.h>
#include <stdio.h>
#include "linalg.h"
/* C prototype for LAPACK routine DGELS */
void dgels_(const char * trans, const int * m, const int * n, const int *
nrhs, double * A, const int * lda, double * B, const int * ldb, double * work,
int * lwork,int * info);
int main(int argc, char * argv[]) {
vector_t * b_t = NULL;
matrix_t * A_t = NULL;
char trans = 'N';
int m, n, nrhs, mb, lda, ldb, info, lwork;
double optwork;
double * work;
// we read the matrix A and the vector b:
b_t = read_vector("b.txt");
A_t = read_matrix("A.txt");
m = A_t-> m; //number of rows in A
n = A_t-> n; //number of columns in A
nrhs = 1; //number of columns in B (will always be 1, since we read b_t with read_vector)
mb = b_t -> n; //number of rows in B
if (mb != m ) { //end program if A and B doesn't have the same number of rows
free(A_t);
free(b_t);
fprintf(stderr, "Sorry, but the matrix A and the vector b have incompatible dimensions. Good Bye!\n");
exit(EXIT_FAILURE);
}
//We make A and B into the wanted input form for the dgels_-function:
double * B = b_t -> v;
double ** A = A_t ->A;
lda = m;
ldb = mb;
//we calculate the optimal size of the work array:
lwork = -1;
dgels_(&trans, &n, &m, &nrhs, *A, &lda, B, &ldb, &optwork, &lwork, &info);
lwork = (int)optwork;
//we allocate space for the work array:
work = (double*)malloc( lwork*sizeof(double));
//solving the least squares problem:
dgels_(&trans, &n, &m, &nrhs, *A, &lda, B, &ldb, work, &lwork, &info);
//Check whether there was an successful exit:
if (info > 0){
fprintf(stderr, "Sorry, but illegal arguments were used, and therefore a least square solution cannot be computes. Good Bye!\n");
exit(EXIT_FAILURE);
} else if(info < 0){
fprintf(stderr, "Sorry, but A doesn't have full rank, and therefore a least square solution cannot be computed. Good Bye!\n");
exit(EXIT_FAILURE);
}
//Saving the least square problem as a vector_t:
vector_t * x = NULL;
x->n = mb;
x->v = B;
print_vector(x);
//Free memory
free_vector(b_t);
free_matrix(A_t);
free_vector(x);
return(EXIT_SUCCESS);
}
I am using the functions read_matrix, read_vector, print_vector, print_matrix and free_vector, which is why I use the struct vector_t and matrix_t:
typedef struct vector {
unsigned long n; /* length of vector */
double * v; /* pointer to array of length n */
} vector_t;
typedef struct matrix {
unsigned long m; /* number of rows */
unsigned long n; /* number of columns */
double ** A; /* pointer to two-dimensional array */
} matrix_t;
I don't think that anything is wrong with read_vector and read_matrix because I can easily do this and use print_vector or print_matrix before I do all of the other operations.
You dereference a NULL pointer here, causing the segfault:
//Saving the least square problem as a vector_t:
vector_t * x = NULL;
x->n = mb;
x->v = B;
Maybe you should use/create a new vector_t instead of just a pointer to a vector_t?
I have the CSR coordinates of a matrix.
/* alloc space for COO matrix */
int *coo_rows = (int*) malloc(K.n_rows * sizeof(int));
int *coo_cols = (int*) malloc(K.n_rows * sizeof(int));
float *coo_vals = (float*) malloc(K.n_rows * sizeof(float));
/*Load coo values*/
int *rowptrs = (int*) malloc((N_unique+1)*sizeof(int));
int *colinds = (int*) malloc(K.n_rows *sizeof(int));
double *vals = (double*) malloc(K.n_rows *sizeof(double));
/* take csr values */
int job[] = {
2, // job(1)=2 (coo->csr with sorting)
0, // job(2)=1 (one-based indexing for csr matrix)
0, // job(3)=1 (one-based indexing for coo matrix)
0, // empty
n1, // job(5)=nnz (sets nnz for csr matrix)
0 // job(6)=0 (all output arrays filled)
};
int info;
mkl_scsrcoo(job, &n, vals, colinds, rowptrs, &n1, coo_vals, coo_rows, coo_cols, &info);
assert(info == 0 && "Converted COO->CSR");
Now I want to apply the mkl_dcsrmm function to compute C := alpha*A*B + beta*C with beta = 0;
/* function declaration */
void mkl_dcsrmm (char *transa, MKL_INT *m, MKL_INT *n, MKL_INT *k, double *alpha, char *matdescra, double *val, MKL_INT *indx, MKL_INT *pntrb, MKL_INT *pntre, double *b, MKL_INT *ldb, double *beta, double *c, MKL_INT *ldc);
Since now I have.
int A_rows = ..., A_cols = ..., C_cols = ...
double alpha = 1.0;
mkl_dcsrmm ((char*)"N", &A_rows, &C_cols, &A_cols, &alpha, char *matdescra, vals, coo_cols, rowptrs, colinds , double *b, MKL_INT *ldb, double *beta, double *c, MKL_INT *ldc);
I found some difficulties on filling the inputs. Could you please help me to fill the rest of the inputs?
A specific input for which I want to go in more details is the matdescra. I borrowed the following code from cspblas_ccsr example
char matdescra[6];
matdescra[0] = 'g';
matdescra[1] = 'l';
matdescra[2] = 'n';
matdescra[3] = 'c';
but I have some questions about that. The matrix A I am working is not triangular and the initialization of this char array engage you to make such a declaration, how should I configure the parameters of the matdescra array?
Here is what I use, and what works for me.
char matdescra[6] = {'g', 'l', 'n', 'c', 'x', 'x'};
/* https://software.intel.com/sites/products/documentation/hpc/mkl/mklman/GUID-34C8DB79-0139-46E0-8B53-99F3BEE7B2D4.htm#TBL2-6
G: General. D: Diagonal
L/U Lower/Upper triangular (ignored with G)
N: non-unit diagonal (ignored with G)
C: zero-based indexing.
*/
Complete Example
Here is a complete example. I first create a random matrix by filling a dense matrix with a specified density of Non-Zero elements. Then I convert it to a sparse matrix in CSR-format. Finally, I do the multiplication using mkl_dcsrmm. As a possible check (check not done), I do the same multiplication using the cblas_dgemm function with the dense matrix.
#include "mkl.h"
#include "mkl_spblas.h"
#include <stddef.h> // For NULL
#include <stdlib.h> // for rand()
#include <assert.h>
#include <stdio.h>
#include <limits.h>
// Compute C = A * B; where A is sparse and B is dense.
int main() {
MKL_INT m=10, n=5, k=11;
const double sparsity = 0.9; ///< #param sparsity Values below which are set to zero (sampled from uniform(0,1)-distribution).
double *A_dense;
double *B;
double *C;
double alpha = 1.0;
double beta = 0.0;
const int allignment = 64;
// Seed the RNG to always be the same
srand(42);
// Allocate memory to matrices
A_dense = (double *)mkl_malloc( m*k*sizeof( double ), allignment);
B = (double *)mkl_malloc( k*n*sizeof( double ), allignment);
C = (double *)mkl_malloc( m*n*sizeof( double ), allignment);
if (A_dense == NULL || B == NULL || C == NULL) {
printf("ERROR: Can't allocate memory for matrices. Aborting... \n\n");
mkl_free(A_dense);
mkl_free(B);
mkl_free(C);
return 1;
}
// Initializing matrix data
int i;
int nzmax = 0;
for (i = 0; i < (m*k); i++) {
double val = rand() / (double)RAND_MAX;
if ( val < sparsity ) {
A_dense[i] = 0.0;
} else {
A_dense[i] = val;
nzmax++;
}
}
for (i = 0; i < (k*n); i++) {
B[i] = rand();
}
for (i = 0; i < (m*n); i++) {
C[i] = 0.0;
}
// Convert A to a sparse matrix in CSR format.
// INFO: https://software.intel.com/sites/products/documentation/hpc/mkl/mklman/GUID-AD67DD8D-4C22-4232-8D3F-AF97DC2ABBC8.htm#GUID-AD67DD8D-4C22-4232-8D3F-AF97DC2ABBC8
MKL_INT job[6];
job[0] = 0; // convert TO CSR.
job[1] = 0; // Zero-based indexing for input.
job[2] = 0; // Zero-based indexing for output.
job[3] = 2; // adns is a whole matrix A.
job[4] = nzmax; // Maximum number of non-zero elements allowed.
job[5] = 3; // all 3 arays are generated for output.
/* JOB: conversion parameters
* m: number of rows of A.
* k: number of columns of A.
* adns: (input/output). Array containing non-zero elements of the matrix A.
* lda: specifies the leading dimension of adns. must be at least max(1, m).
* acsr: (input/output) array containing non-zero elements of the matrix A.
* ja: array containing the column indices.
* ia length m+1, rowIndex.
* OUTPUT:
* info: 0 if successful. i if interrupted at i-th row because of lack of space.
*/
int info = -1;
printf("nzmax:\t %d\n", nzmax);
double *A_sparse = mkl_malloc(nzmax * sizeof(double), allignment);
if (A_sparse == NULL) {
printf("ERROR: Could not allocate enough space to A_sparse.\n");
return 1;
}
MKL_INT *A_sparse_cols = mkl_malloc(nzmax * sizeof(MKL_INT), allignment);
if (A_sparse_cols == NULL) {
printf("ERROR: Could not allocate enough space to A_sparse_cols.\n");
return 1;
}
MKL_INT *A_sparse_rowInd = mkl_malloc((m+1) * sizeof(MKL_INT), allignment);
if (A_sparse_rowInd == NULL) {
printf("ERROR: Could not allocate enough space to A_sparse_rowInd.\n");
return 1;
}
mkl_ddnscsr(job, &m, &k, A_dense, &k, A_sparse, A_sparse_cols, A_sparse_rowInd, &info);
if(info != 0) {
printf("WARNING: info=%d, expected 0.\n", info);
}
assert(info == 0);
char transa = 'n';
MKL_INT ldb = n, ldc=n;
char matdescra[6] = {'g', 'l', 'n', 'c', 'x', 'x'};
/* https://software.intel.com/sites/products/documentation/hpc/mkl/mklman/GUID-34C8DB79-0139-46E0-8B53-99F3BEE7B2D4.htm#TBL2-6
G: General. D: Diagonal
L/U Lower/Upper triangular (ignored with G)
N: non-unit diagonal (ignored with G)
C: zero-based indexing.
*/
mkl_dcsrmm(&transa, &m, &n, &m, &alpha, matdescra, A_sparse, A_sparse_cols,
A_sparse_rowInd, &(A_sparse_rowInd[1]), B, &ldb, &beta, C, &ldc);
// The same computation in dense format
cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
m, n, k, alpha, A_dense, k, B, n, beta, C, n);
mkl_free(A_dense);
mkl_free(A_sparse);
mkl_free(A_sparse_cols);
mkl_free(A_sparse_rowInd);
mkl_free(B);
mkl_free(C);
return 0;
}
I'm new to multithreading had my first lesson yesterday. So I've wrote a program to get the average of 4 big arrays , each array is a thread and the main waits for all the threads and gives the average of the 4 arrays. This is possible because each thread gives the average of one array. The array is just a headerfile with a float array.
It compiles but gives me a segmentation error and I don't see why.
#include "gemiddelde.h"
#include <stdlib.h>
#include <stdio.h>
float *gemiddelde(void *arg)
{
float *a;
int i;
a = (float *)arg;
float * som;
for( i = 0; i < 100000; i++)
*som += a[i];
*som = *som / 100000;
return som;
}
int main()
{
pthread_t t1,t2,t3,t4;
float * som1, * som2, * som3, * som4, *result;
pthread_create(&t1,NULL,gemiddelde,a1);
pthread_create(&t2,NULL,gemiddelde,a2);
pthread_create(&t3,NULL,gemiddelde,a3);
pthread_create(&t4,NULL,gemiddelde,a4);
pthread_join(t1,som1);
pthread_join(t2,som2);
pthread_join(t3,som3);
pthread_join(t4,som4);
usleep(1);
*result = *som1 + *som2 + *som3 + *som4;
printf("Gemiddelde is: %f ", *result);
return 0;
}
Can someone help me?
Kind regards,
In
*result = *som1 + *som2 + *som3 + *som4;
result is used unitialized. Make it a plain float instead of a pointer.
From your current code, segfault occurs because som* aren't initialized -- they are dangling pointers.
Your code is very problematic, because the thread code requires memory to store the result, and as it stands your code is plain wrong because it doesn't have any memory and just dereferences a dangling pointer. But even allocating memory inside the thread is not a great idea, because it's not clear who is responsible for it and who will clean it up. So it's much better to allocate all your required memory in the main function. First some boiler plate to set up the thread argument data:
typedef struct thread_arg_type_
{
float * data;
size_t len;
float retval;
} thread_arg_type;
thread_arg_type * create_thread_arg(size_t n)
{
thread_arg_type * result = malloc(sizeof(thread_arg_type));
if (!result) return NULL;
float * const p = malloc(n * sizeof(float));
if (!p)
{
free(result);
return NULL;
}
result->len = n;
result->data = p;
return result;
}
void free_thread_arg(thred_arg_type * r)
{
if (r) free(r->data);
free(r);
}
Now here's how we use it:
int main()
{
thread_arg_type * arg;
pthread_t t;
arg = create_thread_arg(array1_size);
pthread_create(&t, NULL, getmiddle, arg);
// ...
pthread_join(t, NULL);
printf("The result is: %f.\n", arg->retval);
free_thread_arg(arg);
}
And finally we must adapt getmiddle:
void * getmiddle(thread_arg_t * arg)
{
arg->retval = 0;
for(unsigned int i = 0; i != arg->len; ++i)
arg->retval += arg->data[i];
arg->retval /= arg->len;
return NULL;
}