I keep passing in and returning the dirs_later_array. When I get to "new_size=..." in the else block, I end up with new_size of 2 the second time around. So far so good. But when I do a realloc
dirs_later_array = realloc(dirs_later_array,
new_size * sizeof(struct dirs_later*));
the sizeof remains at 4, the size of the pointer, for dirs_later_array. I'm able to succesfully store at dirs_later_array[1] but that value keeps getting overwritten the next time I go into the function.
struct dirs_later** add_struct(const char *findme, struct dirent *dptr,
struct stat *this_lstat, char *relative_path, const char *type_str,
struct dirs_later **dirs_later_array) {
struct dirs_later *new_dir = malloc(sizeof(struct dirs_later));
check_realloc_dirs_error(new_dir);
if (strcmp(dptr->d_name, ".")) { //Dir and not same directory
//Copy the relative path to the struct
char *relative_path2;
relative_path2 = malloc(strlen(relative_path) + 1);
check_realloc_error(relative_path2);
strcpy(relative_path2, relative_path);
//if (strlen(relative_path) > 0)
// relative_path2[strlen(relative_path) - 1] = '\0';
if (NULL != new_dir) {
new_dir->findme = findme;
new_dir->dptr = dptr;
new_dir->st_mode = this_lstat->st_mode;
new_dir->relative_path = relative_path2;
new_dir->type_str = type_str;
}
int new_size = 0;
/*
//Check if this is the first element in the struct
if (sizeof(dirs_later_array) / sizeof(struct dirs_later*) == 1) {
new_size = 1;
}
*/
if (dirs_later_array == NULL) {
dirs_later_array = malloc(sizeof(struct dirs_later*)); //Store the directory structures or process later
check_realloc_arr_error(*dirs_later_array);
new_size = 1;
} else {
//Add directories to directories array
new_size = (((sizeof(dirs_later_array) + sizeof(struct dirs_later*)))/sizeof(struct dirs_later*));
//printf("new size: %d",new_size);
}
dirs_later_array = realloc(dirs_later_array,
new_size * sizeof(struct dirs_later*));
check_realloc_arr_error(dirs_later_array);
dirs_later_array[new_size - 1] = new_dir;
}
return dirs_later_array;
}
Operator sizeof is a compile time feature and it only checks the static size of an expression. So for pointer it only returns the size of that pointer which is 4 on your platform. sizeof does not measure the size of a dynamically allocated data. There is no standard feature in C to get the size of dynamically allocated data.
Your sizeof(struct dirs_later*) should be changed to sizeof(struct dirs_later) - as before!
Also the sizeof is a compile time feature. You need a structure like this to hold the size
struct my_dirs
struct dirs_later *dirs;
int size;
};
Initialise it like this
struct my_dirs directories;
directories.size = 0;
directories.dirs = NULL;
Then to add (note realloc can take NULL as a parameter
directories.dirs = realloc(directories.dirs,
(++directories.size) * sizeof(struct dirs_later));
This would also simplify your code.
Related
I am solving binary tree paths leet code programming question 257. I am having issue for one of the larger input where my code is getting segmentation fault. I suspect that there is an problem with my realloc but I am not able to figure it out.
Below is my approach:
Initially I started by dynamically allocating 80 bytes of memory of type char (80/8 = 10 rows)and storing the returned address to char **res variable.
char ** res = (char **)malloc(sizeof(char *) * sum);
I am calling findpath function recursively to find all the binary tree paths. Whenever one path is found , I dynamic allocate 100 bytes for each row index.
res[resIdx] = (char *)malloc(sizeof(char) * 100);
I have one global variable resIdx which points to the current row index where I copy the found binary tree path and increment the global variable resIdx.
if the resIdx becomes greater then total number of rows which was previously allocated then I do realloc of the memory but it looks like realloc is getting failed.
if (resIdx >= sum)
{
sum = sum + 10;
res = (char **)realloc(res,sizeof(char *) * sum); //Any issue here?
}
Can anyone please help me to figure out what's wrong I am doing in my code. Below is my full code
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int sum;
int resIdx;
void findpath (struct TreeNode* root, int *ls,int ls_idx,char **res);
char ** binaryTreePaths(struct TreeNode* root, int* returnSize){
if (root == NULL)
{
*returnSize = 0;
return NULL;
}
resIdx = 0;
sum = 10;
char ** res = (char **)malloc(sizeof(char *) * sum);
int ls[100];
findpath(root,&ls[0],0,res);
*returnSize = resIdx;
return &res[0];
}
void findpath (struct TreeNode* root, int *ls,int ls_idx,char **res)
{
char temp[100];
int l=0,i=0;
if (root->left == NULL && root->right == NULL)
{
ls[ls_idx] = root->val;
ls_idx+=1;
if (resIdx >= sum)
{
sum = sum + 10;
res = (char **)realloc(res,sizeof(char *) * sum);
}
res[resIdx] = (char *)malloc(sizeof(char) * 100);
while (i < ls_idx)
{
if (i==0)
{
l = l + sprintf(&temp[l], "%d", ls[i]);
}
else
{
l = l + sprintf(&temp[l], "->%d", ls[i]);
}
i++;
}
strcpy(res[resIdx],temp);
resIdx++;
return;
}
ls[ls_idx] = root->val;
if (root->left != NULL)
{
findpath(root->left,ls,ls_idx+1,res);
}
if (root->right != NULL)
{
findpath(root->right,ls,ls_idx+1,res);
}
return;
}
The last argument to your findPath function is declared as a char** type; thus, when you make the call findpath(root,&ls[0],0,res); in binaryTreePaths, where the res variable is a char** type, a copy of that pointer is passed to the findPath function (most likely, but not necessarily, by placing that copy on the stack).
Then, if reallocation is required, the res = (char **)realloc(res,sizeof(char *) * sum); line in that function overwrites the value in the passed copy and, at the same time (if the call is successful – vide infra), will (probably) invalidate (i.e. free) the memory referenced by the previous address in that res copy. Thus, when control returns to the calling binaryTreePaths function, its own version of res will not have been modified and will remain pointing to that (now invalid) memory.
So, in order for your findPath function to be able to modify the given res argument, that must be passed as a pointer – in this case, a pointer to a char**, which will be of type char***; then, when called, you will need to pass the address of the res variable in binaryTreePaths.
Note also that directly overwriting a pointer in a call to realloc, as you have done in the line of code quoted above is dangerous. This is because, should that call fail, then you have lost the original data pointer (it will have been overwritten with NULL) and error recovery will be very difficult. You should save the return value in a temporary variable and only replace your original if the call succeeds.
With the code you have provided, I cannot properly test for any other errors but, taking the points above in hand, the below is a possible fix. See also: Do I cast the result of malloc?
int sum;
int resIdx;
void findpath(struct TreeNode* root, int* ls, int ls_idx, char*** res); // Note last argument type!
char** binaryTreePaths(struct TreeNode* root, int* returnSize)
{
if (root == NULL) {
*returnSize = 0;
return NULL;
}
resIdx = 0;
sum = 10;
char** res = malloc(sizeof(char*) * sum);
int ls[100];
findpath(root, &ls[0], 0, &res); // Pass ADDRESS of res
*returnSize = resIdx;
return &res[0];
}
void findpath(struct TreeNode* root, int* ls, int ls_idx, char*** res)
{
char temp[100];
int l = 0, i = 0;
if (root->left == NULL && root->right == NULL) {
ls[ls_idx] = root->val;
ls_idx += 1;
if (resIdx >= sum) {
sum = sum + 10;
char** test = realloc(*res, sizeof(char*) * sum);
if (test == NULL) {
// Handle/signal error
return;
}
*res = test; // Only replace original if realloc succeeded!
}
(*res)[resIdx] = malloc(sizeof(char) * 100);
while (i < ls_idx) {
if (i == 0) {
l = l + sprintf(&temp[l], "%d", ls[i]);
}
else {
l = l + sprintf(&temp[l], "->%d", ls[i]);
}
i++;
}
strcpy((*res)[resIdx], temp);
resIdx++;
return;
}
ls[ls_idx] = root->val;
if (root->left != NULL) {
findpath(root->left, ls, ls_idx + 1, res);
}
if (root->right != NULL) {
findpath(root->right, ls, ls_idx + 1, res);
}
return;
}
Trying to add another element to a struct array in C (Windows specific, using VS2019 Community). Works fine, until I try to assign the return value of realloc to the original array. The code in main (declarations and initialization, as well as calling code) is as follows:
// server.h
struct server {
wchar_t* name;
wchar_t ip_address[16];
int port;
};
// main.c
static int nb_servers = 0;
static struct server* servers = NULL;
void add_server(wchar_t* name, wchar_t ip_address[16], wchar_t* port)
{
struct server newserver;
newserver.name = name;
wcsncpy(newserver.ip_address, ip_address, 16);
char* port_char = malloc(6);
if (port_char == NULL) {
exit(EXIT_FAILURE);
}
size_t i;
wcstombs_s(&i, port_char, 6, port, _TRUNCATE);
int port_int = 0;
str2int(&port_int, port_char, 10);
newserver.port = port_int;
// add to servers
nb_servers = server_add(&servers, &newserver, nb_servers);
}
Then in another file, this is where I try to add the new server to the list:
// server.c
int server_add(struct server** servers, struct server* myserver, int nb_servers)
{
struct server* tmp = (struct server*) realloc(*servers, (nb_servers + 1) * sizeof(struct server));
if (tmp == NULL) {
exit(EXIT_FAILURE);
}
tmp[nb_servers].name = (wchar_t*) calloc(strlen(myserver->name), sizeof(wchar_t));
if (tmp[nb_servers].name == NULL) {
exit(EXIT_FAILURE);
}
wcsncpy(tmp[nb_servers].name, myserver->name, strlen(myserver->name));
wcsncpy(tmp[nb_servers].ip_address, myserver->ip_address, 16);
tmp[nb_servers].port = myserver->port;
*servers = tmp; // this only copies the first value [0]
// also tried **servers = *tmp and other combinations, nothing seems to work.
return ++nb_servers;
}
But only the first value is 'copied', or rather only servers[0] point to a valid object. However, tmp[0] to tmp[nb_servers - 1] are valid and contain the correct data. I'm using a similar reallocation mechanism to shrink the array in a remove_server method and that same reassignment works in that case.
Question:
How to correctly add a struct item to an array of structs by dynamically reallocating memory?
When ever I try to access data in memory that I've acquired using malloc, the data is corrupted
I'm writing a program that reads Linux directories and writes the names of the files and sub-directories in a "string array" (char** array in c). It operates using dirent.h functionalities like readdir(). readdir returns a dirent structure that has a dname[256] that's the name of a file/sub-directory in the target directory. I equate the dirent string(char*) to an index of a malloced position in a char** array
I basically have a walk_path() function that reads the directory entries and writes their names into a malloced location then return that location
data_t* walk_path(char* path) {
int size = 0;
if(path == NULL){
printf("NULL path\n");
return NULL;
}
struct dirent* entry;
DIR* dir_l = opendir(path);
if(dir_l == NULL) {
char** data = (char**)malloc(sizeof(char*) * 2);
data[0] = path;
data_t* ret = (data_t*)malloc(sizeof(data_t));
ret->data = data;
ret->size = 1;
return ret;
}
while((entry = readdir(dir_l)) != NULL) {
if(!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
continue;
size++;
}
closedir(dir_l);
char** data = (char**)malloc(sizeof(char*) * size + 1);
int loop_v = 0;
dir_l = opendir(path);
while((entry = readdir(dir_l)) != NULL && loop_v < size) {
if(!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
continue;
data[loop_v] = entry->d_name;
loop_v++;
}
closedir(dir_l);
data_t* ret = (data_t*)malloc(sizeof(data_t*));
ret->size = (size_t)size;
ret->data = data;
return ret;
}
and a merge path function that can take two directories and write their data into a single array
char** merge_path(char* path, char* path2) {
data_t* path_data = walk_path(path);
data_t* path2_data = walk_path(path2);
if(path_data == NULL || path2_data == NULL) {
printf("Merge failed, couldn't get path data\n");
return NULL;
}
char** new_dir_info = (char**)malloc(sizeof(char*) * (path2_data->size + path_data->size) );
if(new_dir_info == NULL)
return NULL;
int loop = 0;
while(loop < path_data->size) {
new_dir_info[loop] = path_data->data[loop];
loop++;
}
loop = 0;
while(loop < path2_data->size) {
new_dir_info[loop + path_data->size] = path2_data->data[loop];
loop++;
}
free(path_data);
free(path2_data);
return new_dir_info;
}
The char** array that the merge path function returns always has corrupted data, that is the characters in the character arrays are corrupted and not the pointers themselves, though I expect it to have the strings passed to it from the directory entries it instead has random strings.
I've stepped through the code and found that the data gets corrupted in merge path function, the source of the error could still originate from walk_path().
This
data_t* ret = (data_t*)malloc(sizeof(data_t*));
ought to be
data_t* ret = (data_t*)malloc(sizeof(data_t));
Generally in C void-pointers do not need to be casted, so all casts to malloc in your code can be dropped, which made the above line look like:
data_t* ret = malloc(sizeof(data_t*));
More over to rule out bugs like this one better step away from doubling the type to mallocate inside the call to malloc(), but better use the variable to allocate to along with the dereferencing operator, like this:
data_t* ret = malloc(sizeof *ret);
Also this line
data[loop_v] = entry->d_name;
copies a pointer to the entry name, not the name itself.
Consider using
data[loop_v] = strdup(entry->d_name);
which dynamically allocates room for a copy of where entry->d_name points to.
Alternatively instead of
char**data;
define
char (*data)[sizeof entry->d_name]; /* Array of pointers to char[as many char as entry->d_name is defined to have] */
or
char (*data)[sizeof ((struct dirent*)NULL)->d_name]; /* Array of pointers to char[as many char as entry->d_name is defined to have] */
and allocate to it like this (following the above proposed pattern):
data = malloc((size /* + 1 */) * sizeof *data); /* Not sure what the idea behind this +1 is. */
And instead of
data[loop_v] = strdup(entry->d_name);
do
strcpy(data[loop_v], entry->d_name);
If going this route you need to adjust the definition of data_t.data accordingly.
I just wrote a nice library that handles nicely a dynamic array allocated on heap in C. It supports many operations, is relatively simple to use "feeling" almost like a regular good old array. It is also easy to simulate many data structures based on it (stacks, queues, heaps, etc...)
It can handle arrays of any type, but the problem is that there's only a single type per compilation. C doesn't have templates, so it's impossible to have for example dynamic arrays of ints and dynamic arrays of chars in the same program, which is a problem.
I haven't found any real solution, everything that I found involved void*, and NO, I do NOT want an array of void pointers. It's nice to be able to put pointers, but I also want to be able to have an array of a raw data type. (such that you can add for example, 3, and access it like : array.data[i]
Should I :
Copy/paste the library once for every type I want to use (horrible, but it'll work and be efficient)
Make it a giant macro, that I can expand with the type I want (so it'll have the same effect as 1, but be somewhat elegant and usable)
Have the size of pointed elements be a variable that is part of the dynamic array structure. Will work mostly but there will be a problem with functions taking and returning the dynamic array type directly. void* will not always be a viable option
Abandon the idea and use C++ instead whenever I need such advanced features
The library works like this : Usage
/* Variable length array library for C language
* Usage :
* Declare a variable length array like this :
*
* da my_array;
*
* Always initialize like this :
*
* da_init(&da); // Creates a clean empty array
*
* Set a length to an array :
*
* da_setlength(&da, n); // Note : if elements are added they'll be uninitialized
* // If elements are removed, they're permanently lost
*
* Always free memory before it goes out of scope (avoid mem leaks !)
*
* da_destroy(&da);
*
* Access elements much like a normal array :
* - No boundary checks : da.data[i]
* - With boundary checks (debug) : da_get(data, i)
*
* da.length; // Return the current length of the variable length array (do NOT set the length by affecting this !! Use da_setlength instead.)
*
* You can add single elements at the end and beginning of array with
*
* da_add(&da, value); // Add at the end
* da_push(&da, value); // Add at the front
*
* Retrieve values at the end and front of array (while removing them) with
*
* da_remove(&da); // From the end
* da_pop(&da); // From the front
*
* Concatenate it with a standard array or another variable length array of same type with
*
* da_append(&da, array, array_length); // Standard array
* da_append(&da, &db); // Another variable length array
*/
Implementation (I'm sorry it's huge, but I have to give it for completeness of the question)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// Increment by which blocks are reserved on the heap
#define ALLOC_BLOCK_SIZE 16
// The type that the variable length array will contain. In this case it's "int", but it can be anything really (including pointers, arrays, structs, etc...)
typedef int da_type;
// Commend this to disable all kinds of bounds and security checks (once you're sure your program is fully tested, gains efficiency)
#define DEBUG_RUNTIME_CHECK_BOUNDS
// Data structure for variable length array variables
typedef struct
{
da_type *start; // Points to start of memory allocated region
da_type *data; // Points to logical start of array
da_type *end; // Points to end of memory allocated region
size_t length; // Length of the array
}
da;
// Initialize variable length array, allocate 2 blocks and put start pointer at the beginning
void da_init(da *da)
{
da_type *ptr = malloc(ALLOC_BLOCK_SIZE * sizeof(da_type));
if(ptr == 0) exit(1);
da->start = ptr;
da->data = ptr;
da->end = da->start + ALLOC_BLOCK_SIZE;
da->length = 0;
}
// Set the da size directly
void da_setlength(da *da, size_t newsize)
{
if(newsize % ALLOC_BLOCK_SIZE != 0)
newsize += ALLOC_BLOCK_SIZE - newsize % ALLOC_BLOCK_SIZE;
ptrdiff_t offs = da->data - da->start;
da_type *ptr = realloc(da->start, newsize * sizeof(da_type));
if(!ptr) exit(1);
da->start = ptr;
da->data = ptr + offs;
da->end = ptr + newsize;
da->length = newsize;
}
// Destroy the variable length array (basically just frees memory)
void da_destroy(da* da)
{
free(da->start);
#ifdef DEBUG_RUNTIME_CHECK_BOUNDS
da->start = NULL;
da->data = NULL;
da->end = NULL;
da->length = 0;
#endif
}
// Get an element of the array with it's index
#ifdef DEBUG_RUNTIME_CHECK_BOUNDS
//Get an element of the array with bounds checking
da_type da_get(da *da, unsigned int index)
{
if(index >= da->length)
{
printf("da error : index %u is out of bounds\n", index);
exit(1);
}
return da->data[index];
}
//Set an element of the array with bounds checking
void da_set(da *da, unsigned int index, da_type data)
{
if(index >= da->length)
{
printf("da error : index %u is out of bounds\n", index);
exit(1);
}
da->data[index] = data;
}
#else
//Get an element of the array without bounds checking
#define da_get(da, index) ((da)->data[(index)])
//Set an element of the array without bounds checking
#define da_set(da, index, v) (da_get(da, index) = v)
#endif
// Add an element at the end of the array
void da_add(da *da, da_type i)
{ // If no more memory
if(da->data + da->length >= da->end)
{ // Increase size of allocated memory block
ptrdiff_t offset = da->data - da->start;
ptrdiff_t newsize = da->end - da->start + ALLOC_BLOCK_SIZE;
da_type *ptr = realloc(da->start, newsize * sizeof(da_type));
if(!ptr) exit(1);
da->data = ptr + offset;
da->end = ptr + newsize;
da->start = ptr;
}
da->data[da->length] = i;
da->length += 1;
}
// Remove element at the end of the array (and returns it)
da_type da_remove(da *da)
{
#ifdef DEBUG_RUNTIME_CHECK_BOUNDS
if(da->length == 0)
{
printf("Error - try to remove item from empty array");
exit(1);
}
#endif
//Read last element of the array
da->length -= 1;
da_type ret_value = da->data[da->length];
//Remove redundant memory if there is too much of it
if(da->end - (da->data + da->length) > ALLOC_BLOCK_SIZE)
{
ptrdiff_t offset = da->data - da->start;
ptrdiff_t newsize = da->end - da->start - ALLOC_BLOCK_SIZE;
da_type *ptr = realloc(da->start, newsize * sizeof(da_type));
if(!ptr) exit(1);
da->data = ptr + offset;
da->end = ptr + newsize;
da->start = ptr;
}
return ret_value;
}
// Add element at the start of array
void da_push(da *da, da_type i)
{ //If array reaches bottom of the allocated space, we need to allocate more
if(da->data == da->start)
{
ptrdiff_t newsize = da->end - da->start + ALLOC_BLOCK_SIZE;
da_type *ptr = realloc(da->start, newsize * sizeof(da_type));
if(!ptr) exit(1);
memmove(ptr + ALLOC_BLOCK_SIZE, ptr, da->length * sizeof(da_type));
da->data = ptr + ALLOC_BLOCK_SIZE;
da->start = ptr;
da->end = ptr + newsize;
}
// Store element at start of array
da->length += 1;
da->data -= 1;
da->data[0] = i;
}
//Remove 1st element of array (and return it)
da_type da_pop(da *da)
{
#ifdef DEBUG_RUNTIME_CHECK_BOUNDS
if(da->length == 0)
{
printf("Error - try to remove item from empty array");
exit(1);
}
#endif
da_type ret_value = da->data[0];
da->length -= 1;
da->data += 1;
ptrdiff_t offset = da->data - da->start;
if(offset > ALLOC_BLOCK_SIZE)
{
ptrdiff_t newsize = da->end - da->start - ALLOC_BLOCK_SIZE;
da_type *ptr = realloc(da->start, newsize * sizeof(da_type));
if(!ptr) exit(1);
memmove(ptr + offset - ALLOC_BLOCK_SIZE, ptr + offset, da->length * sizeof(da_type));
da->data = ptr + offset - ALLOC_BLOCK_SIZE;
da->start = ptr;
da->end = ptr + newsize;
}
return ret_value;
}
// Append array t to s
void da_array_append(da *s, const da_type *t, size_t t_len)
{
if((s->length + t_len) > (s->end - s->start))
{ // Should reserve more space in the heap
ptrdiff_t offset = s->data - s->start;
ptrdiff_t newsize = s->length + t_len;
// Guarantees that new size is multiple of alloc block size
if(t_len % ALLOC_BLOCK_SIZE != 0)
newsize += ALLOC_BLOCK_SIZE - (t_len % ALLOC_BLOCK_SIZE);
da_type *ptr = malloc(newsize * sizeof(da_type));
if(!ptr) exit(1);
memcpy(ptr, s->data, s->length * sizeof(da_type));
memcpy(ptr + s->length, t, t_len * sizeof(da_type));
free(s->start);
s->data = ptr;
s->start = ptr;
s->end = ptr + newsize;
}
else
// Enough space in heap buffer -> do it the simple way
memmove(s->data + s->length, t, t_len * sizeof(da_type));
s->length += t_len;
}
// Append a da is a particular case of appending an array
#define da_append(s, t) da_array_append(s, (t)->data, (t)->length)
What I would do is fall back to preprocessor hackage. You can definitely achieve something like templates in C++ by adding type information when necessary.
struct da_impl {
size_t len;
size_t elem_size;
size_t allocsize; // or whatever
};
void da_init_impl(struct da_impl *impl, size_t elem_size)
{
impl->len = 0;
impl->elem_size = elem_size;
impl->allocsize = 0;
}
#define DA_TEMPLATE(t) struct { da_impl impl; t *data; }
#define da_init(a) da_init_impl(&a.impl, sizeof(*a.data))
// etc.
Then you can use it like this:
DA_TEMPLATE(int) intArray;
da_init(intArray);
da_append(intArray, 42);
int foo = intArray.data[0];
One drawback is that this creates an anonymous structure which you can't really use outside of its scope, but maybe you can live with that...
Use a union for your generic data...
typedef union
{
int *pIntArr;
double *pDblArr;
struct *pStructArr;
... // Etc.
} genericData;
...and use a struct to hold this so you can also include what data your generic data union is holding and its length.
typedef struct
{
genericData data;
int dataType; // 0 == int, 1 == double, 2 == etc.
int dataLength; // Number of elements in array
} genericDataType;
I am currently working on a project for a course in C programming and have run into a problem. I am still quite new to the language C but have experience programming Java.
My program runs into a problem when I try to assign a value to a char * variable member of a struct. The code in question follows below:
void ReadFile(ComponentType * Data, int * numEl, int * numNodes)
{
size_t index;
FILE * dataFile;
char * data;
float * value;
numEl = malloc(sizeof(int *));
numNodes = malloc(sizeof(int*));
Data = malloc(6 * sizeof(ComponentType));
* numEl = 0;
* numNodes = 0;
index = 0;
if((dataFile = fopen("mydata.dat", "r")) == NULL)
puts("Error - file \"mydata.dat\" could not be opened!");
else
{
while(!feof(dataFile))
{
fscanf(dataFile, "%s", data);
Data[index].name = (char *)malloc(strlen(data)+1);
strcpy(Data[index].name, data);
fscanf(dataFile, "%s", data);
Data[index].node1 = (char *)malloc(strlen(data)+1);
strcpy(Data[index].node1, data);
fscanf(dataFile, "%s", data);
Data[index].node2 = (char *)malloc(strlen(data)+1);
strcpy(Data[index].node2, data);
fscanf(dataFile, "%f", value);
Data[index].value = * value;
int i = char2int(CircuitData[index].node1);
if(i > * numNodes)
* numNodes = i;
i = char2int(CircuitData[index].node2);
if(i > * numNodes)
* numNodes = i;
(* numEl)++;
(* numNodes)++;
index++;
}
fclose(dataFile);
}
free(Data);
free(numEl);
free(numNodes);
}
The structure is defined as follows:
typedef struct
{
char * name;
char * node1;
char * node2;
float value;
} ComponentType;
I have run a debug on the program and what basically happens is that the file is read correctly and the value stored in data is correct however printing out Data[index].name either causes a segmentation fault when formatted as a char * or, in the debug program, prints out 0x0. In short, the values read from the file are not being copied into the structure variable I want them in.
Any suggestions/help would be appreciated.
Thank you.
EDIT: I am using Linux 64-bit to code
EDIT 2: I added the entire function in which the error occurs with the changes suggested below
First: when you debug your program, check what sizeof(data) is.
You will be surprised to find it is 8 (the size of a pointer), and NOT 6 (the size you allocated)
This is because sizeof measures the size of the type, and data is a char*, (aka. a pointer).Pointers are 8-bytes. (on a 64-bit system. Other systems are different)
This causes you to allocate 8 bytes for Data[index].name.
Next: You cannot copy data from one array to another using the = operator, as you tried to do with:
Data[index].name = data;
To do it properly:
fscanf(dataFile, "%s", data);
// Measure the length of data, and allocate enough space (including the null-termiantor)
Data[index].name = malloc(strlen(data) + 1);
// Copy from data into Data[index].name. For greater safety, look into strcpy_s
strcpy(Data[index].name, data);