context: https://stackoverflow.com/a/34528438/15603477
The original post left some realloc code unfinished in read_solid
function, inside if(strcmp("endfacet", line) == 0) {}
. trying to finish this part. but failed.
Almost the same as original post code.
Problem:
In if((*sol)->nfacets == (*sol)->maxfacets) {}
code block, I need realloc a struct inner struct.
if I set FACETS = 3 then a single solid struct pointer can only hold 3 facet pointer. Now I want to resize/reallocated to make it can hold more facets pointers.
/*
https://stackoverflow.com/questions/34522831/scanf-stops-working-abruptly/34528438#34528438
gcc \
-Wpointer-arith -Werror=vla -Wendif-labels \
-Wimplicit-fallthrough -Wmissing-format-attribute \
-Wcast-function-type -Wshadow=compatible-local \
-Wformat-security -Wno-format-truncation -Wno-stringop-truncation \
array_struct96.c &&./a.out dat/solid.txt
valgrind ./a.out dat/solid.txt
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<errno.h>
#include<math.h>
/* constants - num dimensions, initial facets
* allocated within each solid, and the max
* chars per-line for fgets to read
*/
enum{NDIM = 3, FACETS = 3, MAXC= 256};
/* facets struct - declared as pointer member of
* struct solid allowing additional allocation to
* hold as many normal/vertexes as required.
*/
typedef struct facet{
double normal[NDIM];
double vertex[NDIM][NDIM];
}facet;
/* struct solid holds the solid's name,
* a pointer to an array of stuct facet,
* the number of facets containing data, and
* the maximum presently allocated.
*/
typedef struct solid{
char *name;
facet *facets;
size_t nfacets;
size_t maxfacets;
}solid;
/* function prototypes */
solid *create_solid();
solid *read_solid(solid **sol, FILE *fp);
void print_solid(solid *sol);
void free_solid(solid *sol);
double xstrtod(char *str, char **ep);
/* simple allocate/initialize function
* return must be assigned to pointer
*/
solid *create_solid()
{
size_t i;
solid *sol = calloc(1,sizeof *sol);
sol->facets = calloc(FACETS, sizeof *(sol->facets));
sol->nfacets = 0;
sol->maxfacets = FACETS;
for(i = 0; i < FACETS; i++){
memset((sol->facets)[i].normal, 0,NDIM * sizeof(double));
memset((sol->facets)[i].vertex, 0,NDIM * NDIM * sizeof(double));
}
return sol;
}
/* simple print of normals & vertexes to stdout */
void print_solid(solid *sol)
{
if(!sol){
fprintf(stderr,"printf_solid() error: invalid parameter 'sol'.\n");
return;
}
size_t i,j;
printf("Normal and vertexes for solid: %s\n", sol->name);
printf("Total size of faces=%ld\n", sol->nfacets);
for(i = 0; i < 5; i++){
printf("record %ld: ", i+1);
printf(
"\nnormal[%3zu]:%10.4f\t%10.4f\t%10.4f\n",i
,sol->facets[i].normal[0]
,sol->facets[i].normal[1]
,sol->facets[i].normal[2]
);
for(j = 0; j < NDIM; j++)
printf("vertex[%3zu]:%10.4f\t%10.4f\t%10.4f\n"
,j
,sol->facets[i].vertex[j][0]
,sol->facets[i].vertex[j][1]
,sol->facets[i].vertex[j][2]
);
}
}
void free_solid(solid *sol)
{
if(sol->name) free(sol->name);
if(sol->facets) free(sol->facets);
if(sol) free(sol);
}
/* string to double with error checking. */
double xstrtod(char *str, char **ep)
{
errno = 0;
double val = strtod(str,ep);
/* Check for various possible errors */
if((errno == ERANGE && (val == HUGE_VAL || val == HUGE_VALL)) ||
(errno != 0 && val == 0)){
perror("strtod");
exit(EXIT_FAILURE);
}
if(ep && *ep == str){
fprintf(stderr,"No double were found.\n");
exit(EXIT_FAILURE);
}
return val;
}
int main (int argc, char **argv) {
solid *sol = NULL; /* pointer to hold values */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open */
fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
return 1;
}
if (read_solid (&sol, fp)) { /* read data from file */
print_solid (sol); /* print data read */
free_solid (sol); /* free all memory */
}
if (fp != stdin) fclose (fp); /* close if not stdin */
return 0;
}
/* read_solid takes the poiner address for a struct solid,
* and will read all normal and vertexes into the struct,
* updating 'nfacets' with the number of facets for which
* there is data, and will validate each read and conversion
* of values from string to double. retuns filled struct on
* success, NULL otherwise
*/
solid *read_solid(solid **sol, FILE *fp)
{
char line[MAXC] = {0}; /* temporary line buffer */
size_t idx = 0, vidx = 0; /* line & vertex indexes */
if(!*sol) *sol = create_solid(); /* allocate & initialize struct */
while(fgets(line,MAXC,fp)) /* read each line in file */
{
size_t len = 0;
char *p, *ep;
p = ep = line;
len = strlen(line); /* get length & remove '\n' */
if(line[len - 1] == '\n')
line[--len] = 0;
if(!(ep = strchr(line,' '))) /* test if space in line */
{ /* if endfacet, update nfacets */
if(strcmp("endfacet", line) == 0)
{
(*sol)->nfacets++;
if((*sol)->nfacets == (*sol)->maxfacets)
{
fprintf(stderr,"read_solid() warning: limit readed\n");
printf("(*sol)->nfacets=%ld\n", (*sol)->nfacets);
// sol->facets = calloc(FACETS, sizeof *(sol->facets));
printf("2 * ((*sol)->maxfacets:%ld\n",2 * (*sol)->maxfacets);
void *tmp = realloc ( (*sol)->facets, 2 * ( (*sol)->maxfacets ) * sizeof *(*sol)->facets);
if (!tmp) { /* if realloc fails, original pointer still valid */
perror ("realloc-sales"); /* throw error */
return (*sol); /* return current pointer */
} /* (don't exit or return NULL) */
(*sol)->facets = tmp; /* assign reallocated block to (*sol)->facets */
/* (optional) zero newly allocated memory */
// memset ((*sol)->facets + (*sol)->nfacets, 0, ((*sol)->maxfacets) * sizeof *((*sol)->facets));
(*sol)->maxfacets *= 2; /* update (*sol)->maxfacets to new size */
printf("this part do called\n");
break;
}
}
goto processed;
}
if(strncmp("solid",line,ep - p) == 0)
{
(*sol)->name = strdup(ep + 1);
goto processed;
}else if(strncmp("facet",line, ep - p) == 0)
{
size_t i;
while(*ep &&(*ep < '0' || *ep > '9')) ep++; /* skip no digit value */
if(!*ep){
fprintf(stderr,"read_solid() error: facet normal no values\n");
return NULL;
}
p = ep;
for(i = 0; i < NDIM; i++){ /* convert to double & validate */
/* for which sol index.
for a specific index of sol
then assign double to normal.*/
(*sol)->facets[(*sol)->nfacets].normal[i] = xstrtod(p,&ep);
p = ep;
}
goto processed;
}else if(strncmp("vertex", line, ep - p) == 0)
{ /* read vertex values */
size_t i;
p = ep + 1;
for(i = 0; i< NDIM; i++){/* convert to double & validate */
(*sol)->facets[(*sol)->nfacets].vertex[vidx][i] = xstrtod(p,&ep);
p = ep;
}
vidx = vidx < 2 ? vidx + 1 : 0; /* update/reset vertex index */
goto processed;
}else if(strncmp("outer",line,ep - p) == 0){ /* skip line begin with outer*/
goto processed;
}else if(strncmp("endsolid",line, ep - p) == 0){ /* skip line begin with endsolid*/
goto processed;
}else{
fprintf(stderr,"read_solid() warning: invalid line at '%3zu'\n",idx);
}
processed:
idx++;
}
if(!(*sol)->nfacets){
fprintf(stderr,"read_solid() error: no data read.\n");
free_solid(*sol);
return NULL;
}
printf("idx=%ld\n", idx);
return *sol;
}
In print_sold function. for(i = 0; i < 5; i++)
0,1,2
is ok. but 3,4 print
record 4:
normal[ 3]: 0.0000 0.0000 0.0000
vertex[ 0]: 0.0000 0.0000 0.0000
vertex[ 1]: 0.0000 0.0000 0.0000
vertex[ 2]: 0.0000 0.0000 0.0000
record 5:
normal[ 4]: 0.0000 0.0000 0.0000
vertex[ 0]: 0.0000 0.0000 0.0000
vertex[ 1]: 0.0000 0.0000 0.0000
vertex[ 2]: 0.0000 0.0000 0.0000
I modified dat/solid.txt
file, so all print should be no zero value. Which mean the realloc part failed.