CUDA C allocating GPU memory for a struct of structs [duplicate] - c

I have a structure with arrays of structures inside in C, and I need a copy of that in the GPU. For that I am writing a function that makes some cudaMalloc and cudaMemcpys of the variables in the struct from host to device.
A simple version (the real one has various structs and variables/arrays inside) of the struct is:
struct Node {
float* position;
};
struct Graph{
unsigned int nNode;
Node* node;
unsigned int nBoundary;
unsigned int* boundary;
};
My problem is that I must be doing something wrong in the memory allocation and copy of the struct. When I copy the variables withing Graph, I can see that they are properly copied (by accessing it in a kernel as in the example below). For example, I can check that graph.nBoundary=3.
However, I can only see this if I do not allocate and copy the memory of Node *. If I do, I get -858993460 instead of 3. Interestingly, Node * is not wrongly allocated, as I can inspect the value of say graph.node[0].pos[0] and it has the correct value.
This only happens with the graph.nBoundary. All the other variables remain with the correct numerical values, but this one gets "wronged" when running the cudaMemcpy of the Node*.
What am I doing wrong and why does this happen? How do I fix it?
Let me know if you need more information.
MCVE:
#include <algorithm>
#include <cuda_runtime_api.h>
#include <cuda.h>
// A point, part of some elements
struct Node {
float* position;
};
struct Graph{
unsigned int nNode;
Node* node;
unsigned int nBoundary;
unsigned int* boundary;
};
Graph* cudaGraphMalloc(const Graph* inGraph);
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
{
if (code != cudaSuccess)
{
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
__global__ void testKernel(Graph* graph,unsigned int * d_res){
d_res[0] = graph->nBoundary;
};
int main()
{
// Generate some fake data on the CPU
Graph graph;
graph.node = (Node*)malloc(2 * sizeof(Node));
graph.boundary = (unsigned int*)malloc(3 * sizeof(unsigned int));
for (int i = 0; i < 3; i++){
graph.boundary[i] = i + 10;
}
graph.nBoundary = 3;
graph.nNode = 2;
for (int i = 0; i < 2; i++){
// They can have different sizes in the original code
graph.node[i].position = (float*)malloc(3 * sizeof(float));
graph.node[i].position[0] = 45;
graph.node[i].position[1] = 1;
graph.node[i].position[2] = 2;
}
// allocate GPU memory
Graph * d_graph = cudaGraphMalloc(&graph);
// some dummy variables to test on GPU.
unsigned int * d_res, *h_res;
cudaMalloc((void **)&d_res, sizeof(unsigned int));
h_res = (unsigned int*)malloc(sizeof(unsigned int));
//Run kernel
testKernel << <1, 1 >> >(d_graph, d_res);
gpuErrchk(cudaPeekAtLastError());
gpuErrchk(cudaMemcpy(h_res, d_res, sizeof(unsigned int), cudaMemcpyDeviceToHost));
printf("%u\n", graph.nBoundary);
printf("%d", h_res[0]);
return 0;
}
Graph* cudaGraphMalloc(const Graph* inGraph){
Graph* outGraph;
gpuErrchk(cudaMalloc((void**)&outGraph, sizeof(Graph)));
//copy constants
gpuErrchk(cudaMemcpy(&outGraph->nNode, &inGraph->nNode, sizeof(unsigned int), cudaMemcpyHostToDevice));
gpuErrchk(cudaMemcpy(&outGraph->nBoundary, &inGraph->nBoundary, sizeof(unsigned int), cudaMemcpyHostToDevice));
// copy boundary
unsigned int * d_auxboundary, *h_auxboundary;
h_auxboundary = inGraph->boundary;
gpuErrchk(cudaMalloc((void**)&d_auxboundary, inGraph->nBoundary*sizeof(unsigned int)));
gpuErrchk(cudaMemcpy(d_auxboundary, h_auxboundary, inGraph->nBoundary*sizeof(unsigned int), cudaMemcpyHostToDevice));
gpuErrchk(cudaMemcpy(&outGraph->boundary, d_auxboundary, sizeof(unsigned int *), cudaMemcpyDeviceToDevice));
//Create nodes
Node * auxnode;
gpuErrchk(cudaMalloc((void**)&auxnode, inGraph->nNode*sizeof(Node)));
// Crate auxiliary pointers to grab them from host and pass them to device
float ** d_position, ** h_position;
d_position = static_cast<float **>(malloc(inGraph->nNode*sizeof(float*)));
h_position = static_cast<float **>(malloc(inGraph->nNode*sizeof(float*)));
for (int i = 0; i < inGraph->nNode; i++){
// Positions
h_position[i] = inGraph->node[i].position;
gpuErrchk(cudaMalloc((void**)&d_position[i], 3 * sizeof(float)));
gpuErrchk(cudaMemcpy(d_position[i], h_position[i], 3 * sizeof(float), cudaMemcpyHostToDevice));
gpuErrchk(cudaMemcpy(&auxnode[i].position, d_position[i], sizeof(float *), cudaMemcpyDeviceToDevice));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// If I comment the following section, nBoundary can be read by the kernel
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
gpuErrchk(cudaMemcpy(&outGraph->node, auxnode, inGraph->nNode*sizeof(Node *), cudaMemcpyDeviceToDevice));
return outGraph;
}

The problem is in the function cudaGraphMalloc where you are trying to allocate device memory to the members of outGraph which has already been allocated on the device. In process of doing so, you are de-referencing a device pointer on host which is illegal.
To allocate device memory to members of struct type variable which exists on the device, we first have to create a temporary host variable of that struct type, then allocate device memory to its members, and then copy it to the struct which exists on the device.
I have answered a similar question here. Please take a look at it.
The fixed code may look like this:
#include <algorithm>
#include <cuda_runtime.h>
#include <cuda.h>
// A point, part of some elements
struct Node {
float* position;
};
struct Graph {
unsigned int nNode;
Node* node;
unsigned int nBoundary;
unsigned int* boundary;
};
Graph* cudaGraphMalloc(const Graph* inGraph);
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
{
if (code != cudaSuccess)
{
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
__global__ void testKernel(Graph* graph, unsigned int * d_res) {
d_res[0] = graph->nBoundary;
};
int main()
{
// Generate some fake data on the CPU
Graph graph;
graph.node = (Node*)malloc(2 * sizeof(Node));
graph.boundary = (unsigned int*)malloc(3 * sizeof(unsigned int));
for (int i = 0; i < 3; i++) {
graph.boundary[i] = i + 10;
}
graph.nBoundary = 3;
graph.nNode = 2;
for (int i = 0; i < 2; i++) {
// They can have different sizes in the original code
graph.node[i].position = (float*)malloc(3 * sizeof(float));
graph.node[i].position[0] = 45;
graph.node[i].position[1] = 1;
graph.node[i].position[2] = 2;
}
// allocate GPU memory
Graph * d_graph = cudaGraphMalloc(&graph);
// some dummy variables to test on GPU.
unsigned int * d_res, *h_res;
cudaMalloc((void **)&d_res, sizeof(unsigned int));
h_res = (unsigned int*)malloc(sizeof(unsigned int));
//Run kernel
testKernel << <1, 1 >> >(d_graph, d_res);
gpuErrchk(cudaPeekAtLastError());
gpuErrchk(cudaMemcpy(h_res, d_res, sizeof(unsigned int), cudaMemcpyDeviceToHost));
printf("%u\n", graph.nBoundary);
printf("%u\n", h_res[0]);
return 0;
}
Graph* cudaGraphMalloc(const Graph* inGraph)
{
//Create auxiliary Graph variable on host
Graph temp;
//copy constants
temp.nNode = inGraph->nNode;
temp.nBoundary = inGraph->nBoundary;
// copy boundary
gpuErrchk(cudaMalloc((void**)&(temp.boundary), inGraph->nBoundary * sizeof(unsigned int)));
gpuErrchk(cudaMemcpy(temp.boundary, inGraph->boundary, inGraph->nBoundary * sizeof(unsigned int), cudaMemcpyHostToDevice));
//Create nodes
size_t nodeBytesTotal = temp.nNode * sizeof(Node);
gpuErrchk(cudaMalloc((void**)&(temp.node), nodeBytesTotal));
for (int i = 0; i < temp.nNode; i++)
{
//Create auxiliary node on host
Node auxNodeHost;
//Allocate device memory to position member of auxillary node
size_t nodeBytes = 3 * sizeof(float);
gpuErrchk(cudaMalloc((void**)&(auxNodeHost.position), nodeBytes));
gpuErrchk(cudaMemcpy(auxNodeHost.position, inGraph->node[i].position, nodeBytes, cudaMemcpyHostToDevice));
//Copy auxillary host node to device
Node* dPtr = temp.node + i;
gpuErrchk(cudaMemcpy(dPtr, &auxNodeHost, sizeof(Node), cudaMemcpyHostToDevice));
}
Graph* outGraph;
gpuErrchk(cudaMalloc((void**)&outGraph, sizeof(Graph)));
gpuErrchk(cudaMemcpy(outGraph, &temp, sizeof(Graph), cudaMemcpyHostToDevice));
return outGraph;
}
Be advised that you will have to keep the host copies of internal device pointers (i.e. the auxiliary host variables). This is because you will have to free the device memory later and since you will only have a device copy of Graph in the main code, you won't be able to access its members from the host to call cudaFree on them. In this case the variable Node auxNodeHost (created in each iteration) and Graph temp are those variables.
The above code does not do that and is just for demonstration purpose.
Tested on Windows 10, Visual Studio 2015, CUDA 9.2, NVIDIA Driver 397.44.

Related

How to properly make a dynamically allocated multi-array in C

I have been working to create a set of functions that allow for the creation and manipulation of a dynamically allocated array in C for any data type. I have created several functions, but of most relevance to this post are the following functions;
vector_mem_alloc This function is not called directly, but when indirectly called in a wrapper it allocates memory for the array based on the data type
init_vector This function is called directly by a user and is a wrapper around vector_mem_alloc. This function preps data and instantiates certain parameters in the Vector struct.
append_vector This function allows a user to append the 1-D array with scalar values or another already created array.
The code for these working functions is shown below.
vector.h
#ifndef ARRAY_H
#define ARRAY_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef enum
{
FLOAT,
DOUBLE,
CHAR,
INT
} dat_type;
typedef struct
{
void *array; // Pointer to array
size_t len; // Active length of array
size_t size; // Number of allocated indizes
int elem; // Memory consumption per indice
char name[20]; // The array name
dat_type dat;
} Vector;
// --------------------------------------------------------------------------------
void vector_mem_alloc(Vector *array, size_t num_indices);
// --------------------------------------------------------------------------------
Vector init_vector(dat_type dat, size_t num_indices, char *name);
// --------------------------------------------------------------------------------
int append_vector(Vector *array, void *elements, size_t count);
#endif /* ARRAY_H */
vector.c
#include "vector.h"
// Begin code
void vector_mem_alloc(Vector *array, size_t num_indices) {
// Determine the total memory allocation and assign to pointer
void *pointer;
pointer = malloc(num_indices * array->elem);
// If memory is full fail gracefully
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(pointer);
exit(0);
}
// Allocate resources and instantiate Array
else {
array->array = pointer;
array->len = 0;
array->size = num_indices;
}
}
// --------------------------------------------------------------------------------
Vector init_vector(dat_type dat, size_t num_indices, char *name) {
// Determine memory blocks based on data type
int size;
switch(dat) {
case FLOAT:
size = sizeof(float);
break;
case INT:
size = sizeof(int);
break;
case DOUBLE:
size = sizeof(double);
break;
case CHAR:
size = sizeof(char);
break;
default:
printf("Data type not correctly entered, instantiating int array!\n");
size = sizeof(int);
dat = INT;
}
// Allocate indice size and call array_mem_alloc
Vector array;
array.dat = dat;
array.elem = size;
vector_mem_alloc(&array, num_indices);
strncpy(array.name, name, sizeof(array.name));
return array;
}
// --------------------------------------------------------------------------------
int append_vector(Vector *array, void *elements, size_t count) {
// Allocae more memory if necessary
if (array->len + count > array->size) {
size_t size = (array->len + count) * 2;
void *pointer = realloc(array->array, size * array->elem);
// If memory is full return operations
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
return 0;
}
// Allocate memory to variables and increment array size
array->array = pointer;
array->size = size;
}
// Append variables and increment the array length
memcpy((char *)array->array + array->len * array->elem, elements, count * array->elem);
array->len += count;
return 1;
}
main.c
// - This shows an implementation for an integer array, but it works
// for FLOAT, DOUBLE, and CHAR as well.
size_t indices = 10;
char name[6] = "array";
dat_type dtype = INT;
Vector arr_test = init_vector(dtype, indices, name);
int a[3] = {10, 9, 8};
append_vector(&arr_test, &a, 3);
Everything listed above works just fine. However, I am trying to expand the capability of the above code to cover multi-arrays of any data type; however, in the near term I am particularly interested in string arrays. I am trying to add another struct to the vector.h file that references marray[] as a data type of Vector. In the long run, I hope to be able to reference the name of each array in the multi-array and treat it similar to a dictionary. I have tried several function that might allow an interface like shown below, but so far none of them work. Does anyone have any suggestions that I might be able to use as a starting point in building this functionality. My intended addition to the vector.h file is shown below with a main.c implentation that shows how I hope to interface with this.
typedef struct
{
size_t len;
size_t size;
int elem;
dat_type dat;
Vector *marray[];
} MVector;
size_t indices = 10;
dat_type dtype = INT;
MVector arr_test = init_vector(dtype, indices);
int a[3] = {10, 9, 8};
append_vector(&arr_test[0], &a, 3);
int b = 3;
append_vector(&arr_test[1], &b, 1);
append_vector(&arr_test[1], &b, 1);
b = 4;
append_vector(&arr_test[1], &b, 1)
append_vector(&arr_test[1], &b, 1);
// result [[10, 9, 8], [3, 3, 4, 4]]

Segmentation Fault when access to a pointer of struct in struct

I have an issue with pointers to struct that have members that are pointers to struct too.
Browsing the suggested similar questions I found out this:
Accessing elements within a pointer of a struct inside another pointer to a struct
where people suggest to pay attention to allocation memory of the structure.
I think this is done correctly in my code.
typedef struct {
int id_vec;
float *vec_value;
} Vector;
typedef struct cluster{
int id_cluster;
float *centroid;
Vector *patternInCluster;
} Cluster;
int main(void){
Cluster *cluster_ptr= malloc(3 * sizeof(Cluster));
if (cluster_ptr==NULL){
printf("NULL");
}
cluster_ptr->patternInCluster=malloc(2 * sizeof(Vector *));
if (cluster_ptr->patternInCluster==NULL){
printf("NULL");
cluster_ptr->patternInCluster=NULL;
}
float p1[3]={0.0f,1.0f,2.0f};
Vector *somePattern=malloc(2 * sizeof(Vector));
somePattern[0].id_vec=1;
somePattern[0].vec_value=p1;
somePattern[1].id_vec=2;
somePattern[1].vec_value=p1;
}
Then I expect that this statement works:
cluster_ptr[1].patternInCluster[1]=somePattern[1];
But it compiles and produces a Segmentation Fault.
Unexpectedly, the following statement doesn't get errors:
cluster_ptr[0].patternInCluster[1]=somePattern[1];
and a test show me correct result(somePattern[1] id and value)
I tried to debug with gdb but I only can see this:
Program received signal SIGSEGV, Segmentation fault.
0x00005555555547fe in main () at test_struct.c:36
36 cluster_ptr[1].patternInCluster[1]=somePattern[1];
Am I missing some allocation mistakes?
It's because you're not populating things fully.
This line
cluster_ptr->patternInCluster=malloc(2 * sizeof(Vector *));
is the same as saying
cluster_ptr[0].patternInCluster=malloc(2 * sizeof(Vector *));
and really given that cluster_ptr has been allocated as 3 Cluster it would be more clearer in your code to do the latter.
Since cluster_ptr[1].patternInCluster hasn't been given a value, trying to dereference it will lead to undefined behaviour but more likely will result in a segmentation fault.
You do not allocate enough memory:
cluster_ptr->patternInCluster=malloc(2 * sizeof(Vector *));
With patternInCluster being of type Vector *, you should allocate memory to hold elements of type Vector, not Vector*.
cluster_ptr->patternInCluster=malloc(2 * sizeof(Vector));
Your problem is NOT accessing the pointer inside the struct. Your problem is how you are using malloc().
When you have one pointer, you malloc only once:
int *pointer = (int* )malloc(sizeof(int));
*pointer = 1;
printf("*pointer:%d\n", *pointer);
When you have pointer-to-pointer, you malloc() once for the **pointer_to_pointer, but you also have to malloc() once for the *pointer_to_pointer:
int** pointer_to_pointer = (int** )malloc(sizeof(int*));
*pointer_to_pointer = (int* )malloc(sizeof(int));
**pointer_to_pointer = 2;
printf("**pointer:%d\n", **pointer_to_pointer);
And if you have more than one pointer, at the location pointed to by **pointer_to_pointer, you need a for loop to assign memory to every one of those *pointer_to_pointers.
for (unsigned int i = 0; i < 3; i++)
{
*(pointer_to_pointer + i*sizeof(int)) = (int* )malloc(sizeof(int));
}
**(pointer_to_pointer + sizeof(int)) = 3;
**(pointer_to_pointer + 2UL*sizeof(int)) = 4;
printf("**(pointer_to_pointer + sizeof(int):%d\n", **(pointer_to_pointer + sizeof(int)));
printf("**(pointer_to_pointer + 2UL*sizeof(int):%d\n", **(pointer_to_pointer + 2UL*sizeof(int)));
You are mistaken to think that Cluster *cluster_ptr= malloc(3 * sizeof(Cluster)); will automatically/magically assign memory for Cluster[0] and Cluster[1] and Cluster[2].
Your statement actually assigns memory only for Cluster[0], but big enough for 3 Clusters.
So the the modified code will look like this:
#include <string.h>
#include <stdio.h>
#include <malloc.h>
typedef struct {
int id_vec;
float *vec_value;
} Vector;
typedef struct cluster{
int id_cluster;
float *centroid;
Vector **patternInCluster;
} Cluster;
int main(void){
Cluster **cluster_ptr = (Cluster **)malloc(sizeof(Cluster*));
for (long unsigned int i = 0; i < 3; i++) {
cluster_ptr[i] = (Cluster *)malloc(sizeof(Cluster));
if (cluster_ptr[i]==NULL){
printf("NULL");
}
cluster_ptr[i]->patternInCluster = (Vector **) malloc(sizeof(Vector*));
for (long unsigned int j = 0; j < 3; j++) {
(*cluster_ptr)->patternInCluster[j] = (Vector *) malloc(sizeof(Vector));
if ((*cluster_ptr)->patternInCluster[j]==NULL){
printf("NULL");
(*cluster_ptr)->patternInCluster[j]=NULL;
}
}
}
float p1[3]={0.0f,1.0f,2.0f};
Vector *somePattern= (Vector *) malloc(sizeof(Vector));
somePattern[0].id_vec=1;
somePattern[0].vec_value=p1;
somePattern[1].id_vec=2;
somePattern[1].vec_value=p1;
cluster_ptr[1]->patternInCluster[1] = &somePattern[0];
cluster_ptr[0]->patternInCluster[1] = &somePattern[1];
cluster_ptr[1]->patternInCluster[0] = &somePattern[1];
cluster_ptr[2]->patternInCluster[1] = &somePattern[0];
printf("%d\n", cluster_ptr[1]->patternInCluster[1]->id_vec);
printf("%d\n", cluster_ptr[0]->patternInCluster[1]->id_vec);
printf("%d\n", cluster_ptr[1]->patternInCluster[0]->id_vec);
printf("%d\n", cluster_ptr[2]->patternInCluster[1]->id_vec);
return 0;
}
On my system, I just compiled and it builds and runs error-free.

C pass variable size 2-D array to function

I'm trying to refactor my code to make it better/more readable so I'm trying change a 2-D variable array allocation as follows
// OLD CODE
int **map;
map = calloc(number, sizeof(int *));
if (!(map)) {
free(map);
return 1;
}
for (int i = 0; i < number; i++) {
map[i] = calloc(number, sizeof(int));
if (!(map[i])) {
while (--i >= 0) {
free(map[i]);
}
free(map);
return 1;
}
}
// NEW CODE
int (*map)[number] = malloc(sizeof (int[number][number]));
if (!(map)){
free(map);
return 1;
}
The problem is that all my functions that use map take int **map and by changing the declaration of map like i did the IDE tells me incorrect type int[]* instead of int**
What should i use instead of int**? Using int[]* map in the function declaration tells me can't resolve variable map
Turns out the below code is not a C99 alternative #M.M, but a GCC extension.
Undocumented GCC Extension: VLA in struct
As a C99 GCC extension alternative to int (*map)[number] = malloc(sizeof (int[number][number])); for code simplification and maintain compatibility with existing function set, allocate all the memory needed with 1 *alloc() call.
This does require that when code is done with the map, all the memory is free'd with one free(map). Further, individual rows of map[] can no longer be re-allocated, but can be swapped within the map[].
int **map_allocate(size_t row, size_t column) {
struct {
int *ip[row]; // Array of pointers, followed by a ...
int i[row][column]; // 2D array of int
} *u;
u = calloc(1, sizeof *u);
if (u == NULL) {
return NULL;
}
for (size_t i = 0; i<row; i++) {
u->ip[i] = u->i[row];
}
return &u->ip[0];
}
Note: no casting and field i[][] is properly aligned.
To use one allocation with standard code, unlike the other answer, is a bit trickier as one needs to insure that a combined memory allocation of pointers and int needs to meet alignment concerns in the unusual case of int alignment requirements exceed pointer alignment ones. This is more easily shown with long long as below.
If this makes "code easier to read" is left to OP's judgment.
#include <stdlib.h>
#include <stdio.h>
long long **map_allocate_ll(size_t row, size_t column) {
long long **map;
long long *ints;
size_t pointers_sz = sizeof *map * row;
// extend pointer size to `*ints` boundary
pointers_sz = (pointers_sz + sizeof *ints - 1)/sizeof *ints * sizeof *ints;
size_t ints_sz = sizeof *ints * row * column;
printf("psize %zu, isize %zu\n", pointers_sz, ints_sz);
map = calloc(1, pointers_sz + ints_sz);
if (map == NULL) {
return NULL;
}
ints = (void*) ((char*) map + pointers_sz);
printf("map %p\n", (void *) map);
for (size_t i = 0; i<row; i++) {
map[i] = &ints[i * column];
printf("map[%zu] %p\n", i, (void *) map[i]);
}
return map;
}
int main() {
free(map_allocate_ll(5,3));
}
Sample output
psize 24, isize 120
map 0x80081868
map[0] 0x80081880
map[1] 0x80081898
map[2] 0x800818b0
map[3] 0x800818c8
map[4] 0x800818e0

Initializing struct using a function

This is in my main.c
int main(){
int size = 5;
Path Solution;
PathInit(&Solution,size);
printf("Size: %d\n",Solution.size);
printf("top: %d", Solution.top);
}
This is in my path.h
typedef struct{
int size;
int top;
int *item;
}Path;
This is in my path.c
void PathInit(Path *P, int vsize){
P = (Path *)malloc(sizeof(Path));
P->size = vsize;
P->item = (int *)malloc(sizeof(int)*vsize);
P->top = -1;
}
The expected output is
Size: 5
top: -1
However the output is something along the lines of
Size: 3412832
top: 0
Can someone explain why my struct is not initializing properly. Also this isn't my full code but ive narrowed the problem down to these sections. Any help would be great. Thanks
You are using the stack:
Path Solution;
and passing a pointer:
PathInit(&Solution,size);
so you don't need to reserve space with malloc:
void PathInit(Path *P, int vsize){
P = (Path *)malloc(sizeof(Path)); /* Remove this line */
As mentioned in the answer of #Alter Mann's, the issue is that you mess up with the stack storage, which is undefined behaviour. In case you want to use dynamic allocation, you need to pass a pointer to pointer (and btw there is no need to cast the result of malloc in C), so you can modify it in your function, like:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int size;
int top;
int *item;
} Path;
void PathInit(Path **P, int vsize) { // pass pointer to pointer so we can modify it
*P = malloc(sizeof(Path)); // No need (and not recommended) to cast malloc in C
(*P)->size = vsize;
(*P)->item = malloc(sizeof(int) * vsize);
(*P)->top = -1;
}
int main() {
int size = 5;
Path* Solution; // this is now a pointer
PathInit(&Solution, size);
printf("Size: %d\n", Solution->size);
printf("top: %d", Solution->top);
free(Solution->item);
free(Solution);
}
Otherwise you need to return the pointer from your function:
Path* PathInit(int vsize) {
Path* tmp = malloc(sizeof(Path));
tmp->size = vsize;
tmp->item = malloc(sizeof(int) * vsize);
tmp->top = -1;
return tmp;
}
and call it like
Path* Solution;
Solution = PathInit(size);

realloc doesn't work in function

int *f, *l;
int main(){
int *a;
a = calloc(1, sizeof(int));
f = l = a;
put(&a, 1);
put(&a, 3);
put(&a, 2);
_getch();
return 0;
}
void put(int **a, int d){
printf("--%d--", sizeof(*a)); //always == 4
void *tmp = (int *)realloc(*a, sizeof(*a) + sizeof(int));
if (temp) //allocated succesfully
*a = temp;
else
printf("Allocating a failed");
l++;
}
I trying to create a queue model based on int pointers.
I've corrected the sample a bit. But it still failed.
Could you please help?
a is an int pointer (int*), therefore its size if 4 bytes (on your machine) you should keep track of the size of allocated memory.
For example:
int *f, *l;
int main(){
int *a;
size_tasize = 0;
a = calloc(1, sizeof(int));
f = l = a;
asize = sizeof(int);
put(a, 1, &asize);
put(a, 3, &asize);
put(a, 2, &asize);
_getch();
return 0;
}
void put(int *a, int d, size_t * asize){
printf("--%d--\n", asize); //always == 4
void *tmp = (int *)realloc(a, *asize + sizeof(int));
(*asize) += 4;
if (tmp)
a = tmp; //allocated succesfully
else
printf("Reallocating of 'a' size %d failed\n", asize);
l++;
}
In C, there is no way to know the size of an array which is referenced by a pointer:
int a[25]; // Known size
int *b = a; // Unknown size
so the sizeof() just prints the size of the pointer which is 4 bytes on a 32bit platform.
If you need the size, allocate a structure like so:
struct Mem {
int size;
int a[1];
}
Use sizeof(struct Mem) + sizeof(int) * amount to determine how much memory to allocate, assign it to a pointer. Now you can use the memory with ptr->a[x].
Note that it will allocate a bit more memory that necessary (usually 4 bytes) but this approach works with different alignments, pointer sizes, etc.
sizeof(a) is the size of the pointer, not what a points to.
You are modifying the local variable a within the function, not the variable a in your main function. You either need to return the new value of a from put() or pass in a pointer to your pointer (int **a) to modify it.
For example:
int *put(int *a, int d);
int main(){
int *a;
a = calloc(1, sizeof(int));
a = put(a, 1);
...
}
int *put(int *a, int d){
void *tmp = (int *)realloc(a, sizeof(a) + sizeof(int));
if (tmp)
a = tmp; //allocated succesfully
else
printf("Reallocating of 'a' size %d failed\n", sizeof(a));
return a;
}
sizeof(a) will always return 4 in your case. It returns the size of the pointer, not the size of the memory allocated that the pointer is pointing to.
Instead of doing
if (tmp)
a = tmp;
return tmp and assign it to a in main.
If you want to re-assign a new block to the pointer in a function other then one in which it has been defined , you have to pass a pointer to this pointer or return the newly allocated block and collect it into the same older block in caller function, as otherwise you'd be updating a copy.
The whole concept does not work the way you would it have to.
The sizeof a stuff does not work the way you intend to.
The reallocation itself is wrong, as you don't return the new address to the caller.
You have no information about the length of your data.
I would propose the following:
struct memblock {
unsigned int alloced;
unsigned int len;
int * data;
}
// in order to prealloc
char add_realloc(struct memblock * mb, unsigned int add) {
add += mb->alloced;
int * tmp = realloc(mb->data, sizeof(*mb) + add * sizeof(*(mb->data)));
if (!tmp) return 0;
mb->data = tmp;
mb->alloced = add;
return 1;
}
char put(struct memblock * mb, int d) {
if (mb->len == mb->alloced) {
// realloc
if (!add_realloc(mb, 1)) return 0;
}
mb->data[mb->len++] = d;
return 1;
}
int main(){
struct memblock a = {} // init with all zeros.
// Calling realloc() with a NULL pointer is like malloc().
// we put 3 values. Prealloc for not to have to realloc too often.
if (add_realloc(&a, 3) {
// now we are safe. Don't check the return values - it is guaranteed to be ok.
put(&a, 1);
put(&a, 3);
put(&a, 2);
}
return 0;
}

Resources