Related
I'm having trouble accessing my double pointer struct within my structure.
typedef struct monster
{
char *name;
char *element;
int population;
} monster;
typedef struct region
{
char *name;
int nmonsters;
int total_population;
monster **monsters;
} region;
region **
readRegion (FILE * infile, int *regionCount)
{
region **temp;
char garbage[50];
char garbage2[50];
char rName[50];
int monsterNum;
fscanf (infile, "%d %s", regionCount, garbage);
temp = malloc (*regionCount * sizeof (region *));
for (int i = 0; i < *regionCount; i++)
{
fscanf (infile, "%s%d%s", rName, &monsterNum, garbage2);
temp[i] = createRegion (inFile, rName, monsterNum);
}
return temp;
}
region *
createRegion (FILE * inFile, char *rName, int nMonsters)
{
region *r = malloc (sizeof (region));
char rMonster[50];
int rLength;
r->name = malloc ((strlen (rName) + 1) * sizeof (char));
strcpy (r->name, rName);
r->nmonsters = nMonsters;
for (int i = 0; i < nMonsters; i++)
{
r->monsters.name = (nMonsters * sizeof (r->monsters.name));
fscanf (in, "%s", rMonster);
r->monsters.name = malloc ((strlen (rMonster) + 1) * sizeof (char));
strcpy (r->monsters.name, rMonster);
}
return r;
}
Hopefully my code is readable where you can get the jist of what im trying to do with the monster** monsters pointer in my region struct. Any explnation on how to access and use a double struct pointer within a structure would help.
I've tried to clean up and re-interpret your createRegion to read a lot more like traditional C:
region* createRegion(FILE * inFile, char *rName, int nMonsters) {
region *r = malloc(sizeof(region));
char buffer[1024];
r->name = strdup(rName);
r->nmonsters = nMonsters;
r->monsters = calloc(nMonsters, sizeof(monster*));
for (int i=0; i < nMonsters; i++) {
// Allocate a monster
monster *m = malloc(sizeof(monster));
fscanf(in,"%s", buffer);
m->name = strdup(buffer);
m->element = NULL; // TBD?
m->population = 1; // TBD?
// Put this monster in the monsters pointer array
r->monsters[i] = m;
}
return r;
}
Where the key here is you must allocate the monsters. Here it's done individually, but you could also allocate as a slab:
region* createRegion(FILE * inFile, char *rName, int nMonsters) {
region *r = malloc(sizeof(region));
char buffer[1024];
r->name = strdup(rName);
r->nmonsters = nMonsters;
// Make a single allocation, which is usually what's returned from
// C functions that allocate N of something
monsters* m = calloc(nMonsters, sizeof(monster));
// Normally you'd see a definition like m in the region struct, but
// that's not the case here because reasons.
r->monsters = calloc(nMonsters, sizeof(monster*));
for (int i=0; i < nMonsters; i++) {
fscanf(in,"%s", buffer);
m[i].name = strdup(buffer);
m[i].element = NULL; // TBD?
m[i].population = 1; // TBD?
// Put this monster in the monsters pointer array
r->monsters[i] = &m[i];
}
return r;
}
Note I've switched out the highly quirky strlen-based code with a simple strdup call. It's also very odd to see sizeof(char) used since on any computer you're likely to interface with, be it an embedded microcontroller or a fancy mainframe, that will be 1.
Inasmuch as you are asking about accessing a double pointer inside a structure, I think your issue is mostly about this function:
region *
createRegion (FILE * inFile, char *rName, int nMonsters)
{
region *r = malloc (sizeof (region));
char rMonster[50];
int rLength;
r->name = malloc ((strlen (rName) + 1) * sizeof (char));
strcpy (r->name, rName);
r->nmonsters = nMonsters;
[Point A]
So far, so good, but here you start to run off the rails.
for (int i = 0; i < nMonsters; i++)
{
r->monsters.name = (nMonsters * sizeof (r->monsters.name));
Hold on. r->monsters has type monster **, but you are trying to access it as if it were a monster. Moreover, r->monsters has never had a value assigned to it, so there's very little indeed that you can safely do with it.
I think the idea must be that r->monsters is to be made to point to a dynamically-allocated array of monster *, and that the loop allocates and initializes the monsters, and writes pointers to them into the array.
You need to allocate space for the array, then, but you only need or want to allocate the array once. Do that before the loop, at Point A, above, something like this:
r->monsters = malloc(nMonsters * sizeof(*r->monsters)); // a monster **
Then, inside the loop, you need to allocate space for one monster, and assign a pointer to that to your array:*
r->monsters[i] = malloc(sizeof(*r->monsters[i])); // a monster *
Then, to access the actual monster objects, you need to either dererference and use the direct member selection operator (.) ...
(*r->monsters[i]).name = /* ... */;
... or use the indirect member selection operator (->) ...
r->monsters[i]->name = /* ... */;
. The two are equivalent, but most C programmers seem to prefer the latter style.
At this point, however, I note that in the body of the loop, you seem to be trying to make two separate assignments to the monster's name member. That doesn't make sense, and the first attempt definitely doesn't make sense, because you seem to be trying to assign a number to a pointer.
fscanf (in, "%s", rMonster);
r->monsters.name = malloc ((strlen (rMonster) + 1) * sizeof (char));
strcpy (r->monsters.name, rMonster);
Using the above, then, and taking advantage of the fact that sizeof(char) is 1 by definition, it appears that what you want is
// ...
r->monsters[i]->name = malloc(strlen(rMonster) + 1);
strcpy (r->monsters[i]->name, rMonster);
And finally,
}
return r;
}
Note well that corresponding to the two levels of indirection in type monster **, each access to an individual monster property via r->members requires two levels of derferencing. In the expressions above, one is provided by the indexing operator, [], and the other is provided by the indirect member access operator, ->.
* Or you could allocate space for all of the monsters in one go, before the loop, and inside the loop just initialize them and the array of pointers to them. The use of a monster ** suggests the individual allocation approach, but which to choose depends somewhat on how these will be used. The two options are substantially interchangeable, but not wholly equivalent.
I'm not great with pointers. I know enough to get an array of pointers to char to work, as in the first example below. But I don't want to pass an entire array of pointers, because it takes up too much room on the stack. What I would like to do is pass a single pointer to the memory allocated for the array of pointers. I have no idea how to do this.
This program works:
#include "pch.h"
#include "$StdHdr.h"
#include "TmpTstPtr1.h"
#define SRC_LIN_SIZ 150
int main(int ArgCnt, char * ArgVal[])
{
char InpFilPth[MAX_PATH + 1];
FILE * InpFilPtr;
char ** SrcArr;
unsigned Sub1;
unsigned SrcArrCnt = 0;
strncpy_s(InpFilPth, "TmpTstPtr1.cpp", strlen("TmpTstPtr1.cpp"));
fopen_s(&InpFilPtr, InpFilPth, "r");
SrcArr = (char **)malloc(999999 * sizeof(char *));
LodSrcArr(InpFilPtr, SrcArr, &SrcArrCnt);
for (Sub1 = 0; Sub1 < SrcArrCnt; Sub1++) {
printf("SrcArr[%d] = %s\n", Sub1, SrcArr[Sub1]);
}
fclose(InpFilPtr);
return 0;
}
void LodSrcArr(FILE * InpFilPtr, char ** SrcArr, unsigned * SrcArrCnt)
{
char SrcLin[SRC_LIN_SIZ + 1];
char * GetStrPtr;
GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
while (GetStrPtr != NULL) {
SrcArr[*SrcArrCnt] = (char *)malloc(SRC_LIN_SIZ + 1);
// CpySiz(SrcArr[*SrcArrCnt], strlen(SrcLin) + 1, SrcLin);
errno = strncpy_s(SrcArr[*SrcArrCnt], SRC_LIN_SIZ + 1, SrcLin, strlen(SrcLin));
(*SrcArrCnt)++;
GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
}
}
char * GetStr(char * Str, const int MaxChr, FILE * InpFilPtr)
{
char * InpRtnVal = NULL;
unsigned Sub1;
// Get string from input file. Find the end of the string if something entered.
InpRtnVal = fgets(Str, MaxChr + 1, InpFilPtr);
if (InpRtnVal != NULL) {
Sub1 = 0;
while (Str[Sub1] != '\n' && Str[Sub1] != '\0') {
Sub1++;
}
// Replace newline with null.
if (Str[Sub1] == '\n') {
Str[Sub1] = '\0';
}
}
return InpRtnVal;
The following program doesn't even come close:
#include "pch.h"
#include "$StdHdr.h"
#include "TmpTstPtr2.h"
#define SRC_LIN_SIZ 150
int main(int ArgCnt, char * ArgVal[])
{
char InpFilPth[MAX_PATH + 1];
FILE * InpFilPtr;
char ** SrcArr;
unsigned Sub1;
unsigned SrcArrCnt = 0;
char *** SrcArrPtr = NULL;
strncpy_s(InpFilPth, "TmpTstPtr2.cpp", strlen("TmpTstPtr2.cpp"));
fopen_s(&InpFilPtr, InpFilPth, "r");
SrcArr = (char **)malloc(999999 * sizeof(char *));
SrcArrPtr = &SrcArr;
LodSrcArr(InpFilPtr, SrcArrPtr, &SrcArrCnt);
SrcArrPtr = &SrcArr;
for (Sub1 = 0; Sub1 < SrcArrCnt; Sub1++) {
// printf("SrcArr[%d] = %s\n", Sub1, SrcArr[Sub1]); // got "Exception thrown: read access violation. it was 0xCDCDCDCD."
printf("SrcArr[%d] = %s\n", Sub1, **SrcArrPtr); // get 75 lines of garbage
(**SrcArrPtr) += sizeof(char *);
}
fclose(InpFilPtr);
return 0;
}
void LodSrcArr(FILE * InpFilPtr, char *** SrcArrPtr, unsigned * SrcArrCnt)
{
char SrcLin[SRC_LIN_SIZ + 1];
char * GetStrPtr;
GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
// while (GetStrPtr != NULL and *SrcArrCnt == 0) {
while (GetStrPtr != NULL) {
**SrcArrPtr = (char *)malloc(SRC_LIN_SIZ + 1);
// CpySiz(SrcArr[*SrcArrCnt], strlen(SrcLin) + 1, SrcLin);
errno = strncpy_s(**SrcArrPtr, SRC_LIN_SIZ + 1, SrcLin, strlen(SrcLin));
(**SrcArrPtr) += sizeof(char *);
(*SrcArrCnt)++;
GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
}
}
char * GetStr(char * Str, const int MaxChr, FILE * InpFilPtr)
{
char * InpRtnVal = NULL;
unsigned Sub1;
// Get string from input file. Find the end of the string if something entered.
InpRtnVal = fgets(Str, MaxChr + 1, InpFilPtr);
if (InpRtnVal != NULL) {
Sub1 = 0;
while (Str[Sub1] != '\n' && Str[Sub1] != '\0') {
Sub1++;
}
// Replace newline with null.
if (Str[Sub1] == '\n') {
Str[Sub1] = '\0';
}
}
return InpRtnVal;
}
As the comments say, when I try to access SrcArr via a subscript, I get a run-time error. When I try to access via the pointer, I get garbage. The problem may be where I say SrcArrPtr = &SrcArr;. I don't know if it's significant, but the garbage printed is 4 characters shorter with each subsequent line. As if it's actually printing the array of pointers itself, rather than the strings they point to. I dunno.
The reason I coded it as above is in order to get the program to compile. I've never tried to use 3 pointers before. Is what I'm trying to do even possible? If so, can someone show me how? An explanation of how it works would be nice, but not necessary. (I'm using Visual Studio 2017, though I don't think it matters.)
TIA.
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
void foo(char* bar[10]) { // a real array
for (int i = 0; i < 10; ++i) {
bar[i] = calloc(2, 1);
bar[i][0] = '0' + i;
}
}
void xox(char **qux) { // pointer to some char-pointers on the heap
for (int i = 0; i < 10; ++i) {
qux[i] = calloc(2, 1);
qux[i][0] = '0' + i;
}
}
int main(void)
{
char* bar[10]; // a "real" array
foo(bar);
for (size_t i = 0; i < 10; ++i)
puts(bar[i]);
putchar('\n');
// cleanup:
for (size_t i = 0; i < 10; ++i)
free(bar[i]);
// plan b:
char **qux = calloc(10, sizeof(*qux));
xox(qux);
for (size_t i = 0; i < 10; ++i)
puts(qux[i]);
putchar('\n');
// cleanup:
for (size_t i = 0; i < 10; ++i)
free(qux[i]);
free(qux);
}
What I would like to do is pass a single pointer to the memory
allocated for the array of pointers.
Suppose you have some integers on the heap, like this:
int *integers = (int*)malloc(4 * sizeof(int));
And now suppose you have some pointers, also on the heap:
int **pointers = (int**)malloc(4*sizeof(int*));
Now let's assign the pointers to the addresses of the integers:
pointers[0] = &integers[0];
pointers[1] = &integers[1];
pointers[2] = &integers[2];
pointers[3] = &integers[3];
In this example, pointers is a pointer to an array of pointers (on the heap) pointing to some integers (also on the heap). You can freely pass pointers around and use it in another function.
Or, if you wanted the array of pointer to be on the stack:
int* pointers[4];
pointers[0] = &integers[0];
pointers[1] = &integers[1];
pointers[2] = &integers[2];
pointers[3] = &integers[3];
int **ppointer = pointers;
Now ppointer is also a pointer pointing to an array of pointers that point to some integers on the heap. Just notice that this time, those pointers are on the stack, not on the heap. So if you return from this function, they're out of scope and you may not access them anymore.
You're operating under a misconception. Neither C nor C++ pass a copy of an array to a function, nor can they return an array from a function.
Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression is the address of the first element.
Thus, if you declare an array like
char *ptrs[N];
and pass it to a function as
foo( ptrs );
the expression ptrs is implicitly converted from "N-element array of char *" to "pointer to char *", and what foo actually receives is a pointer to the first element of the array - it's effectively the same as writing
foo( &ptrs[0] );
The prototype can be written as either
void foo( char **ptrs )
or
void foo( char *ptrs[] )
or
void foo( char *ptrs[N] )
In a function parameter declaration, array declarators are "adjusted" to be pointer declarators - IOW, T a[N] and T a[] are both interpreted to mean T *a. This is only true in a function parameter declaration, though.
As a matter of style...
In C, the cast on malloc is unnecessary1, and under C89 it can suppress a useful diagnostic if you forget to include stdlib.h or otherwise don't have a declaration for malloc (or calloc or realloc) in scope. Under C99 and later, you'll get a diagnostic for not having a declaration, but C89 still allowed implicit int declarations, and the cast will prevent the compiler from yelling at you because int and pointer types are not compatible. I bring this up because MS's support for C past C89 is a bit spotty.
To minimize your maintenance burden, it's better to avoid explicitly naming types in a malloc call. You can rewrite
SrcArr = (char **)malloc(999999 * sizeof(char *));
as
SrcArr = malloc( 999999 * sizeof *SrcArr ); // you sure you need that many elements??!
Since SrcArr has type char **, the expression *SrcArr has type char *, so sizeof *SrcArr is the same as sizeof (char **). In general, a malloc call can be written
T *p = malloc( N * sizeof *p );
or
T *p;
...
p = malloc( N * sizeof *p );
The same is true for calloc and realloc.
This is not the cast in C++, since C++ doesn't allow implicit conversion from void * to other pointer types, but if you're writing C++ you shouldn't be using malloc anyway.
I have a dynamically allocated array of structures, 'buff'. Each element is a structure that has a few integer variables and a pointer 'buffer_ptr' which points to another dynamically allocated array of structures. The size of both arrays is given as command line input.
int buffer_size;
int user_num;
struct tuple
{
char userID[5];
char topic[16];
int weight;
};
struct buff_ctrl
{
struct tuple* buffer_ptr;
int in;
int out;
int numItems;
int done;
};
The arrays are created and initialized in main() as follows:
int main(int argc, char* argv[])
{
void *status;
pthread_t mapThd;
if(argc != 4)
{
printf("Input format: ./combiner <buffer_size> <number_of_users> <input_file>\n");
return -1;
}
buffer_size = atoi(argv[1]);
user_num = atoi(argv[2]);
struct buff_ctrl *buff = (struct buff_ctrl*)malloc(user_num * sizeof(struct buff_ctrl));
for(int i=0; i<user_num; i++)
{
struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));
struct tuple *ptr = (struct tuple*)malloc(buffer_size * sizeof(struct tuple));
curr_buff->buffer_ptr = ptr;//points to another array
curr_buff->in = 8;
curr_buff->out = 4;
curr_buff->numItems = 7;
curr_buff->done = 0;
printf("%p\n",curr_buff);
}
Then, I need to pass the 'buff' pointer as an argument when creating thread using pthread_create:
pthread_create(&mapThd, NULL, mapper, (void*)buff);
pthread_join(mapThd, &status);
free(buff);
/*end of main*/
My function pointer is as follows:
void* mapper(void *buff)
{
struct buff_ctrl* arr = (struct buff_ctrl *)buff;
struct buff_ctrl* temp_ptr;
printf("######################################################\n");
for(int k=0; k<user_num; k++)
{
/*Printing just to check values */
temp_ptr = arr + (k*sizeof(struct buff_ctrl));
printf("buffer ptr = %p\n", temp_ptr->buffer_ptr);
printf("in = %d\n", temp_ptr->in);
printf("out = %d\n", temp_ptr->out);
printf("numItems = %d\n", temp_ptr->numItems);
}
printf("######################################################\n");
pthread_exit((void*)buff);
}
But, when I print the values of 'buffer_ptr' from the created thread (only one), for ODD number of user_num, there is always ONE element of the array 'buff' which gives garbage value after pthread_create statement! When the values are checked in main itself after removing calls to pthread, it runs fine.
This line
struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));
should be
struct buff_ctrl* curr_buff = buff + i;
buff + i is pointer arithmetic and the compiler already takes the size of the
object pointed to by buff into consideration. By doing i*sizeof(struct buff_ctrl) you are assigning
a pointer that may be after the allocated memory.
As general suggestion:
Don't cast malloc. And instead of using sizeof(<type>), use sizeof *variable, this is more safe, because
it's easier to make mistakes when writing sizeof(<type>).
So:
struct buff_ctrl *buff = malloc(user_num * sizeof *buff);
...
struct tuple *ptr = malloc(buffer_size * sizeof *ptr);
And you don't need to declare a separate pointer, you can do:
for(int i=0; i<user_num; i++)
{
buff[i].buffer_ptr = malloc(buffer_size * sizeof *buff[i].buffer_ptr);
buff[i].in = 8;
buff[i].out = 4;
buff[i].numItems = 7;
buff[i].done = 0;
}
Also you should always check for the return value of malloc. If it returns
NULL, you cannot access that memory.
This is wrong:
struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));
When you do pointer arithmetic, it operates in units of the size of what the pointer points to, so you don't need to multiply by sizeof. As a result, you're effectively multiplying twice and accessing outside the array bounds.
Just treat buff as an array, rather than dealing with pointers.
for(int i=0; i<user_num; i++)
{
struct tuple *ptr = malloc(buffer_size * sizeof(struct tuple));
buff[i].buffer_ptr = ptr;//points to another array
buff[i].in = 8;
buff[i].out = 4;
buff[i].numItems = 7;
buff[i].done = 0;
}
Also, see Do I cast the result of malloc?
You have a fundamental error.
Pointer arithmetics works by adding the offset in multiples of the pointer type, so adding the offset yourself will not work as you apparently expect it to.
If it was a char * pointer then you would need to add the offset manually, increments would be multiplied by one. But in your case increments by n are multiplied by the size of the pointer base type.
There are times when doing pointer arithmetics with the addition notation makes sense, but most of the time it's much clearer to write index notation instead.
I'm used to PHP, but I'm starting to learn C. I'm trying to create a program that reads a file line by line and stores each line to an array.
So far I have a program that reads the file line by line, and even prints each line as it goes, but now I just need to add each line to an array.
My buddy last night was telling me a bit about it. He said I'd have to use a multidimensional array in C, so basically array[x][y]. The [y] part itself is easy, because I know the maximum amount of bytes that each line will be. However, I don't know how many lines the file will be.
I figure I can make it loop through the file and just increment an integer each time and use that, but I feel that there might be a more simple way of doing it.
Any ideas or even a hint in the right direction? I appreciate any help.
To dynamically allocate a 2D array:
char **p;
int i, dim1, dim2;
/* Allocate the first dimension, which is actually a pointer to pointer to char */
p = malloc (sizeof (char *) * dim1);
/* Then allocate each of the pointers allocated in previous step arrays of pointer to chars
* within each of these arrays are chars
*/
for (i = 0; i < dim1; i++)
{
*(p + i) = malloc (sizeof (char) * dim2);
/* or p[i] = malloc (sizeof (char) * dim2); */
}
/* Do work */
/* Deallocate the allocated array. Start deallocation from the lowest level.
* that is in the reverse order of which we did the allocation
*/
for (i = 0; i < dim1; i++)
{
free (p[i]);
}
free (p);
Modify the above method. When you need another line to be added do *(p + i) = malloc (sizeof (char) * dim2); and update i. In this case you need to predict the max numbers of lines in the file which is indicated by the dim1 variable, for which we allocate the p array first time. This will only allocate the (sizeof (int *) * dim1) bytes, thus much better option than char p[dim1][dim2] (in c99).
There is another way i think. Allocate arrays in blocks and chain them when there is an overflow.
struct _lines {
char **line;
int n;
struct _lines *next;
} *file;
file = malloc (sizeof (struct _lines));
file->line = malloc (sizeof (char *) * LINE_MAX);
file->n = 0;
head = file;
After this the first block is ready to use. When you need to insert a line just do:
/* get line into buffer */
file.line[n] = malloc (sizeof (char) * (strlen (buffer) + 1));
n++;
When n is LINE_MAX allocate another block and link it to this one.
struct _lines *temp;
temp = malloc (sizeof (struct _lines));
temp->line = malloc (sizeof (char *) * LINE_MAX);
temp->n = 0;
file->next = temp;
file = file->next;
Something like this.
When one block's n becomes 0, deallocate it, and update the current block pointer file to the previous one. You can either traverse from beginning single linked list and traverse from the start or use double links.
There's no standard resizable array type in C. You have to implement it yourself, or use a third-party library. Here's a simple bare-bones example:
typedef struct int_array
{
int *array;
size_t length;
size_t capacity;
} int_array;
void int_array_init(int_array *array)
{
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_free(int_array *array)
{
free(array->array);
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_push_back(int_array *array, int value)
{
if(array->length == array->capacity)
{
// Not enough space, reallocate. Also, watch out for overflow.
int new_capacity = array->capacity * 2;
if(new_capacity > array->capacity && new_capacity < SIZE_T_MAX / sizeof(int))
{
int *new_array = realloc(array->array, new_capacity * sizeof(int));
if(new_array != NULL)
{
array->array = new_array;
array->capacity = new_capacity;
}
else
; // Handle out-of-memory
}
else
; // Handle overflow error
}
// Now that we have space, add the value to the array
array->array[array->length] = value;
array->length++;
}
Use it like this:
int_array a;
int_array_init(&a);
int i;
for(i = 0; i < 10; i++)
int_array_push_back(&a, i);
for(i = 0; i < a.length; i++)
printf("a[%d] = %d\n", i, a.array[i]);
int_array_free(&a);
Of course, this is only for an array of ints. Since C doesn't have templates, you'd have to either put all of this code in a macro for each different type of array (or use a different preprocessor such as GNU m4). Or, you could use a generic array container that either used void* pointers (requiring all array elements to be malloc'ed) or opaque memory blobs, which would require a cast with every element access and a memcpy for every element get/set.
In any case, it's not pretty. Two-dimensional arrays are even uglier.
Instead of an array here, you could also use a linked list, The code is simpler, but the allocation is more frequent and may suffer from fragmentation.
As long as you don't plan to do much random access (Which is O(n) here), iteration is about as simple as a regular array.
typedef struct Line Line;
struct Line{
char text[LINE_MAX];
Line *next;
};
Line *mkline()
{
Line *l = malloc(sizeof(Line));
if(!l)
error();
return l;
}
main()
{
Line *lines = mkline();
Line *lp = lines;
while(fgets(lp->text, sizeof lp->text, stdin)!=NULL){
lp->next = mkline();
lp = lp->next;
}
lp->next = NULL;
}
If you are using C you will need to implement the resizing of the array yourself. C++ and the SDL has this done for you. It is called a vector. http://www.cplusplus.com/reference/stl/vector/
While a multidimensional array can solve this problem, a rectangular 2D array would not really be the natural C solution.
Here is a program that initially reads the file into a linked list, and then allocates a vector of pointers of the right size. Each individual character does then appear as array[line][col] but in fact each row is only as long as it needs to be. It's C99 except for <err.h>.
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct strnode {
char *s;
struct strnode *next;
} strnode;
strnode *list_head;
strnode *list_last;
strnode *read1line(void) {
char space[1024];
if(fgets(space, sizeof space, stdin) == NULL)
return NULL;
strnode *node = malloc(sizeof(strnode));
if(node && (node->s = malloc(strlen(space) + 1))) {
strcpy(node->s, space);
node->next = NULL;
if (list_head == NULL)
list_head = node;
else
list_last->next = node;
list_last = node;
return node;
}
err(1, NULL);
}
int main(int ac, char **av) {
int n;
strnode *s;
for(n = 0; (s = read1line()) != NULL; ++n)
continue;
if(n > 0) {
int i;
strnode *b;
char **a = malloc(n * sizeof(char *));
printf("There were %d lines\n", n);
for(b = list_head, i = 0; b; b = b->next, ++i)
a[i] = b->s;
printf("Near the middle is: %s", a[n / 2]);
}
return 0;
}
You can use the malloc and realloc functions to dynamically allocate and resize an array of pointers to char, and each element of the array will point to a string read from the file (where that string's storage is also allocated dynamically). For simplicity's sake we'll assume that the maximum length of each line is less than M characters (counting the newline), so we don't have to do any dynamic resizing of individual lines.
You'll need to keep track of the array size manually each time you extend it. A common technique is to double the array size each time you extend, rather than extending by a fixed size; this minimizes the number of calls to realloc, which is potentially expensive. Of course that means you'll have to keep track of two quantities; the total size of the array and the number of elements currently read.
Example:
#define INITIAL_SIZE ... // some size large enough to cover most cases
char **loadFile(FILE *stream, size_t *linesRead)
{
size_t arraySize = 0;
char **lines = NULL;
char *nextLine = NULL;
*linesRead = 0;
lines = malloc(INITIAL_SIZE * sizeof *lines);
if (!lines)
{
fprintf(stderr, "Could not allocate array\n");
return NULL;
}
arraySize = INITIAL_SIZE;
/**
* Read the next input line from the stream. We're abstracting this
* out to keep the code simple.
*/
while ((nextLine = getNextLine(stream)))
{
if (arraySize <= *linesRead)
{
char **tmp = realloc(lines, arraysSize * 2 * sizeof *tmp);
if (tmp)
{
lines = tmp;
arraySize *= 2;
}
}
lines[(*linesRead)++] = nextLine;
)
return lines;
}
plain C have nice feature - void type pointers, which can be used as pointer to any data type.
But, assume I have following struct:
struct token {
int type;
void *value;
};
where value field may point to char array, or to int, or something else.
So when allocating new instance of this struct, I need:
1) allocate memory for this struct;
2) allocate memory for value and assign it to value field.
My question is - is there ways to declare "array of type void", which can be casted to any another type like void pointer?
All I want is to use "flexible member array" (described in 6.7.2.1 of C99 standard) with ability to casting to any type.
Something like this:
struct token {
int type;
void value[];
};
struct token *p = malloc(sizeof(struct token) + value_size);
memcpy(p->value, val, value_size);
...
char *ptr = token->value;
I suppose declaring token->value as char or int array and casting to needed type later will do this work, but can be very confusing for someone who will read this code later.
Well, sort of, but it's probably not something you want:
struct token {
// your fields
size_t item_size;
size_t length
};
struct token *make_token(/* your arguments */, size_t item_size, size_t length)
{
struct token *t = malloc(sizeof *t + item_size * length);
if(t == NULL) return NULL;
t->item_size = item_size;
t->length = length;
// rest of initialization
}
The following macro can be used to index your data (assuming x is a struct token *):
#define idx(x, i, t) *(t *)(i < x->length ? sizeof(t) == x->item_size ?
(void *)(((char *)x[1]) + x->item_size * i)
: NULL : NULL)
And, if you like, the following macro can wrap your make_token function to make it a little more intuitive (or more hackish, if you think about it that way):
#define make_token(/* args */, t, l) (make_token)(/* args */, sizeof(t), l)
Usage:
struct token *p = make_token(/* args */, int, 5); // allocates space for 5 ints
...
idx(p, 2, int) = 10;
Expanding on AShelly's answer you can do this;
/** A buffer structure containing count entries of the given size. */
typedef struct {
size_t size;
int count;
void *buf;
} buffer_t;
/** Allocate a new buffer_t with "count" entries of "size" size. */
buffer_t *buffer_new(size_t size, int count)
{
buffer_t *p = malloc(offsetof(buffer_t, buf) + count*size);
if (p) {
p->size = size;
p->count = count;
}
return p;
}
Note the use of "offsetof()" instead of "sizeof()" when allocating the memory to avoid wasting the "void *buf;" field size. The type of "buf" doesn't matter much, but using "void *" means it will align the "buf" field in the struct optimally for a pointer, adding padding before it if required. This usually gives better memory alignment for the entries, particularly if they are at least as big as a pointer.
Accessing the entries in the buffer looks like this;
/** Get a pointer to the i'th entry. */
void *buffer_get(buffer_t *t, int i)
{
return &t->buf + i * t->size;
}
Note the extra address-of operator to get the address of the "buf" field as the starting point for the allocated entry memory.
I would probably do this:
struct token {
int type;
void *value;
};
struct token p;
p.value = malloc(value_size);
p.value[0] = something;
p.value[1] = something;
...
edit, actually you have to typecast those p.value[index] = somethings. And/or use a union to not have to typecast.
You can't have an array of 'void' items, but you should be able to do something like what you want, as long as you know value_size when you do the malloc. But it won't be pretty.
struct token {
int type;
void *value;
};
value_size = sizeof(type)*item_count;
struct token *p = malloc(sizeof(struct token) + value_size);
//can't do memcpy: memcpy(p->value, val, value_size);
//do this instead
type* p = (type*)&(p->value);
type* end = p+item_count;
while (p<end) { *p++ = someItem; }
Note that you need an extra address-of operator when you want to get the extra storage.
type *ptr = (type*)&(token->value);
This will 'waste' sizeof(void*) bytes, and the original type of value doesn't really matter, so you may as well use a smaller item. I'd probably typedef char placeholder; and make value that type.
following structure can help you.
struct clib_object_t {
void* raw_data;
size_t size;
};
struct clib_object_t*
new_clib_object(void *inObject, size_t obj_size) {
struct clib_object_t* tmp = (struct clib_object_t*)malloc(sizeof(struct clib_object_t));
if ( ! tmp )
return (struct clib_object_t*)0;
tmp->size = obj_size;
tmp->raw_data = (void*)malloc(obj_size);
if ( !tmp->raw_data ) {
free ( tmp );
return (struct clib_object_t*)0;
}
memcpy ( tmp->raw_data, inObject, obj_size);
return tmp;
}
clib_error
get_raw_clib_object ( struct clib_object_t *inObject, void**elem) {
*elem = (void*)malloc(inObject->size);
if ( ! *elem )
return CLIB_ELEMENT_RETURN_ERROR;
memcpy ( *elem, inObject->raw_data, inObject->size );
return CLIB_ERROR_SUCCESS;
}
More Details : clibutils
Array of type void is not supporting in c/c++.
Example like:
int main() {
void alexa[]; // error: declaration of ‘alexa’ as array of void
return 0;
}
Array of void pointer is supported in c/c++.
Example below:
int main(int argc, char argv*[])
{
void *alexa[100]; // Compiled successfully
return 0;
}