realloc a struct pointer inner struct pointer in c - c

context: https://stackoverflow.com/a/34528438/15603477
The original post left some realloc code unfinished in read_solidfunction, 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.

Here is some heavily amended code that works without any obvious memory faults.
It has several major modifications, and umpteen minor ones (not all of which will be mentioned here):
Using a for loop instead of a while loop in read_solid(), which gets rid of the processed label.
Using multiple subfunctions to make it easier to read the body of the processing loop.
Since the xstrtod() function exits on error (in your code and this code), I've made the code "fail fast" in other places too.
The code reading the 'normal' data no longer skips over '+' or '-' signs.
The function directive() splits the line, isolating the directive from the data after it. This makes it easier to write the list of comparisons, and the code can use strcmp() instead of strncmp().
There's a fairly simple if / else if / … / else chain in the loop, mostly just calling functions that do a task.
I renamed the structure types with an initial capital (Facet, Solid).
The read_solid() function is passed a pre-allocated Solid structure, which simplifies the code.
Because the reading loop breaks when it encounters the endsolid line, it is possible for it to read multiple solids from a single file.
Code:
/* SO 7456-2825 */
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { NDIM = 3, FACETS = 3, MAXC = 256 };
typedef struct Facet
{
double normal[NDIM];
double vertex[NDIM][NDIM];
} Facet;
typedef struct Solid
{
char *name;
Facet *facets;
size_t nfacets;
size_t maxfacets;
} Solid;
static Solid *create_solid(void);
static int read_solid(Solid *sol, FILE *fp);
static void print_solid(Solid *sol);
static void free_solid(Solid *sol);
static double xstrtod(char *str, char **ep);
static Solid *create_solid(void)
{
Solid *sol;
if ((sol = calloc(1, sizeof(*sol))) == NULL ||
(sol->facets = calloc(FACETS, sizeof(sol->facets[0]))) == NULL)
{
free(sol);
return NULL;
}
sol->nfacets = 0;
sol->maxfacets = FACETS;
return sol;
}
static void print_solid(Solid *sol)
{
if (!sol)
{
fprintf(stderr, "%s error: invalid parameter\n", __func__);
return;
}
printf("Normal and vertexes for solid: %s\n", sol->name);
printf("Total size of faces=%zu\n", sol->nfacets);
for (size_t i = 0; i < sol->nfacets; i++)
{
printf("Facet %zu: ", 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 (size_t 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]
);
}
}
}
static void free_solid(Solid *sol)
{
if (sol)
{
free(sol->name);
free(sol->facets);
free(sol);
}
}
static double xstrtod(char *str, char **ep)
{
errno = 0;
double val = strtod(str, ep);
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;
}
/* exits on failure */
static void more_facets(Solid *sol)
{
fprintf(stderr, "%s() warning: limit reached (sol->nfacets = %zu)\n",
__func__, sol->nfacets);
size_t new_facets = 2 * sol->maxfacets;
printf("new_facets = %zu\n", new_facets);
void *tmp = realloc(sol->facets, new_facets * sizeof(sol->facets[0]));
if (tmp == NULL)
{
perror(__func__);
exit(EXIT_FAILURE);
}
sol->facets = tmp;
sol->maxfacets = new_facets;
}
static void read_name(Solid *sol, char *name)
{
sol->name = strdup(name);
if (sol->name == NULL)
{
perror(__func__);
exit(EXIT_FAILURE);
}
}
static void read_normal(Facet *fp, char *ep)
{
while (*ep && !isdigit((unsigned char)*ep) && *ep != '+' && *ep != '-')
ep++;
if (!*ep)
{
fprintf(stderr, "%s(): error: facet normal no values\n", __func__);
return;
}
for (size_t i = 0; i < NDIM; i++)
{
char *p = ep;
fp->normal[i] = xstrtod(p, &ep);
}
}
static void read_vertex(Facet *facet, char *ep, size_t vidx)
{
assert(vidx < NDIM);
char *p = ep;
for (size_t i = 0; i < NDIM; i++)
{
facet->vertex[vidx][i] = xstrtod(p, &ep);
p = ep;
}
}
/* Isolate directive into null-terminated string */
/* Return pointer to data after blank after directive, or null byte */
static char *directive(char *line)
{
char *ep = strchr(line, ' ');
if (ep != NULL)
*ep++ = '\0';
else
ep += strlen(line);
return ep;
}
/*
** Note that the scanning does not enforce the correct sequencing of
** facet, outer, vertex, vertex, vertex, endloop, endfacet
** There are other infelicities that are not detected.
*/
static int read_solid(Solid *sol, FILE *fp)
{
char line[MAXC];
size_t vidx = 0;
for (size_t lineno = 0; fgets(line, sizeof(line), fp) != NULL; lineno++)
{
line[strcspn(line, "\n")] = '\0';
char *ep = directive(line);
if (strcmp("endfacet", line) == 0)
continue;
else if (strcmp("endloop", line) == 0)
continue;
else if (strcmp("outer", line) == 0)
vidx = 0;
else if (strcmp("endsolid", line) == 0)
break;
else if (strcmp("solid", line) == 0)
read_name(sol, ep);
else if (strcmp("facet", line) == 0)
{
assert(sol->nfacets <= sol->maxfacets);
if (sol->nfacets == sol->maxfacets)
more_facets(sol);
read_normal(&sol->facets[sol->nfacets++], ep);
}
else if (strcmp("vertex", line) == 0)
read_vertex(&sol->facets[sol->nfacets - 1], ep, vidx++);
else
{
fprintf(stderr, "%s() warning: invalid directive '%s' at '%3zu' ignored\n",
__func__, line, lineno);
}
}
if (!sol->nfacets)
{
fprintf(stderr, "read_solid() error: no data read.\n");
free_solid(sol);
return -1;
}
printf("idx=%zu\n", sol->nfacets);
return 0;
}
int main(int argc, char **argv)
{
FILE *fp = argc > 1 ? fopen(argv[1], "r") : stdin;
if (fp == NULL)
{
fprintf(stderr, "%s: error: file open failed '%s'\n", argv[0], argv[1]);
return 1;
}
Solid *sol = create_solid();
if (sol == NULL)
{
fprintf(stderr, "%s: error: failed to create solid\n", argv[0]);
}
if (read_solid(sol, fp) == 0)
{
print_solid(sol);
free_solid(sol);
}
if (fp != stdin)
fclose(fp);
return 0;
}
When run on the full-size (24-facet) data file from the prior question, it produces the output:
more_facets() warning: limit reached (sol->nfacets = 3)
more_facets() warning: limit reached (sol->nfacets = 6)
more_facets() warning: limit reached (sol->nfacets = 12)
new_facets = 6
new_facets = 12
new_facets = 24
idx=24
Normal and vertexes for solid: Untitled-56807ca1
Total size of faces=24
Facet 1:
Normal[ 0]: 0.0000 0.0000 -1.0000
Vertex[ 0]: 100.0000 50.0000 0.0000
Vertex[ 1]: 0.0000 0.0000 0.0000
Vertex[ 2]: 0.0000 50.0000 0.0000
Facet 2:
Normal[ 1]: 0.0000 0.0000 -1.0000
Vertex[ 0]: 0.0000 0.0000 0.0000
Vertex[ 1]: 100.0000 50.0000 0.0000
Vertex[ 2]: 100.0000 0.0000 0.0000
Facet 3:
Normal[ 2]: -1.0000 0.0000 0.0000
Vertex[ 0]: 0.0000 50.0000 67.8050
Vertex[ 1]: 0.0000 0.0000 0.0000
Vertex[ 2]: 0.0000 0.0000 67.8050
Facet 4:
Normal[ 3]: -1.0000 0.0000 0.0000
Vertex[ 0]: 0.0000 0.0000 0.0000
Vertex[ 1]: 0.0000 50.0000 67.8050
Vertex[ 2]: 0.0000 50.0000 0.0000
Facet 5:
Normal[ 4]: -0.0000 1.0000 0.0000
Vertex[ 0]: 0.0000 50.0000 67.8050
Vertex[ 1]: 100.0000 50.0000 0.0000
Vertex[ 2]: 0.0000 50.0000 0.0000
Facet 6:
Normal[ 5]: -0.0000 1.0000 0.0000
Vertex[ 0]: 100.0000 50.0000 0.0000
Vertex[ 1]: 0.0000 50.0000 67.8050
Vertex[ 2]: 100.0000 50.0000 67.8050
Facet 7:
Normal[ 6]: 1.0000 0.0000 0.0000
Vertex[ 0]: 100.0000 50.0000 0.0000
Vertex[ 1]: 100.0000 0.0000 67.8050
Vertex[ 2]: 100.0000 0.0000 0.0000
Facet 8:
Normal[ 7]: 1.0000 0.0000 0.0000
Vertex[ 0]: 100.0000 0.0000 67.8050
Vertex[ 1]: 100.0000 50.0000 0.0000
Vertex[ 2]: 100.0000 50.0000 67.8050
Facet 9:
Normal[ 8]: -0.0000 -1.0000 -0.0000
Vertex[ 0]: 100.0000 0.0000 67.8050
Vertex[ 1]: 0.0000 0.0000 0.0000
Vertex[ 2]: 100.0000 0.0000 0.0000
Facet 10:
Normal[ 9]: -0.0000 -1.0000 -0.0000
Vertex[ 0]: 0.0000 0.0000 0.0000
Vertex[ 1]: 100.0000 0.0000 67.8050
Vertex[ 2]: 0.0000 0.0000 67.8050
Facet 11:
Normal[ 10]: 0.8394 0.0000 0.5436
Vertex[ 0]: 100.0000 50.0000 67.8050
Vertex[ 1]: 69.0000 15.5000 115.6740
Vertex[ 2]: 100.0000 0.0000 67.8050
Facet 12:
Normal[ 11]: 0.8394 0.0000 0.5436
Vertex[ 0]: 69.0000 15.5000 115.6740
Vertex[ 1]: 100.0000 50.0000 67.8050
Vertex[ 2]: 69.0000 34.5000 115.6740
Facet 13:
Normal[ 12]: -0.8394 -0.0000 0.5436
Vertex[ 0]: 31.0000 15.5000 115.6740
Vertex[ 1]: 0.0000 50.0000 67.8050
Vertex[ 2]: 0.0000 0.0000 67.8050
Facet 14:
Normal[ 13]: -0.8394 -0.0000 0.5436
Vertex[ 0]: 0.0000 50.0000 67.8050
Vertex[ 1]: 31.0000 15.5000 115.6740
Vertex[ 2]: 31.0000 34.5000 115.6740
Facet 15:
Normal[ 14]: -0.0000 -0.9514 0.3081
Vertex[ 0]: 69.0000 15.5000 115.6740
Vertex[ 1]: 0.0000 0.0000 67.8050
Vertex[ 2]: 100.0000 0.0000 67.8050
Facet 16:
Normal[ 15]: -0.0000 -0.9514 0.3081
Vertex[ 0]: 0.0000 0.0000 67.8050
Vertex[ 1]: 69.0000 15.5000 115.6740
Vertex[ 2]: 31.0000 15.5000 115.6740
Facet 17:
Normal[ 16]: 0.0000 0.9514 0.3081
Vertex[ 0]: 31.0000 34.5000 115.6740
Vertex[ 1]: 100.0000 50.0000 67.8050
Vertex[ 2]: 0.0000 50.0000 67.8050
Facet 18:
Normal[ 17]: 0.0000 0.9514 0.3081
Vertex[ 0]: 100.0000 50.0000 67.8050
Vertex[ 1]: 31.0000 34.5000 115.6740
Vertex[ 2]: 69.0000 34.5000 115.6740
Facet 19:
Normal[ 18]: 0.0000 -0.8820 0.4713
Vertex[ 0]: 50.0000 25.0000 133.4520
Vertex[ 1]: 31.0000 15.5000 115.6740
Vertex[ 2]: 69.0000 15.5000 115.6740
Facet 20:
Normal[ 19]: 0.6832 0.0000 0.7302
Vertex[ 0]: 69.0000 34.5000 115.6740
Vertex[ 1]: 50.0000 25.0000 133.4520
Vertex[ 2]: 69.0000 15.5000 115.6740
Facet 21:
Normal[ 20]: -0.6832 0.0000 0.7302
Vertex[ 0]: 50.0000 25.0000 133.4520
Vertex[ 1]: 31.0000 34.5000 115.6740
Vertex[ 2]: 31.0000 15.5000 115.6740
Facet 22:
Normal[ 21]: -0.0000 -0.0000 1.0000
Vertex[ 0]: 69.0000 15.5000 115.6740
Vertex[ 1]: 31.0000 34.5000 115.6740
Vertex[ 2]: 31.0000 15.5000 115.6740
Facet 23:
Normal[ 22]: -0.0000 -0.0000 1.0000
Vertex[ 0]: 31.0000 34.5000 115.6740
Vertex[ 1]: 69.0000 15.5000 115.6740
Vertex[ 2]: 69.0000 34.5000 115.6740
Facet 24:
Normal[ 23]: -0.0000 0.8820 0.4713
Vertex[ 0]: 50.0000 25.0000 133.4520
Vertex[ 1]: 69.0000 34.5000 115.6740
Vertex[ 2]: 31.0000 34.5000 115.6740
I think that the break you have in the code after allocating more facets was the main cause of your trouble.
If I were working on it further, I'd have a code structure that insisted on the correct sequencing. With the functions in place, it is fairly easy to see how to do this. This would eliminate the vidx in the main loop, which is still pretty ugly. I'd also consider making a structure type for the 3 numbers (struct Point { double x; double y; double z; }; or struct Point { double value[3]; }; or similar, and using that in the Facet structure. It would simplify the argument handling.

Related

fscanf printing unknown values

I am trying to use fscanf to take a text file and simply print it in the same format (eventually it will be used to populate an array of structures).
When I use fscanf it prints some values which are not part of the text and I'm not sure where they are coming from. I have put a small part of the input text file and the output below the code section.
The values I want to print across the page horizontally are all in the first column of the output, which makes me think that its something to do with how I have defined my fprint statement? Each of the correct values in the first column are followed by values which I don't know where have come from.
Any help would be greatly appreciated.
#include <stdlib.h>
int count_lines(char file[]) {
FILE* f = fopen(file, "r"); /* declaration of file pointer */
char x;
int c = 0; /* declaration of variable */
f = fopen(file, "r");
if (f == NULL) {
printf("Cannot open file for reading");
return -1;
}
while ((x = fgetc(f)) != EOF) {
if (x == '\n') {
c = c + 1;
}
}
if (fclose(f) != 0) {
printf("File could not be closed.\n");
return -1;
}
printf("Number of lines = %d\n", c);
return c;
}
struct votes {
char state[100]; /* state name */
long dempv; /* democrats popular votes */
long demev; /* democrats electoral votes */
long reppv; /* republicans popular votes */
long repev; /* republicans electoral votes */
};
void initialise_votes(char file[], struct votes* arr, int nlines) {
FILE* f = fopen(file, "r");
char temp1[20];
long temp2;
long temp3;
long temp4;
long temp5;
if (f == NULL) {
printf("Cannot open file for reading\n");
}
while (fscanf(f, "%s, %ld, %ld, %ld, %ld", temp1, &temp2, &temp3, &temp4, &temp5) != EOF) {
printf("%s\t%ld\t%ld\t%ld\t%ld\n", temp1, temp2, temp3, temp4, temp5);
}
if (fclose(f) != 0) {
printf("File could not be closed.\n");
}
}
int main(void) {
char s_in[] = "uselection2012.txt"; /* input data file */
int nlines;
struct votes* arr;
nlines = count_lines(s_in);
arr = (struct votes*)malloc(sizeof(struct votes) * nlines);
initialise_votes(s_in, arr, nlines);
return 0;
}
Input file:
Alabama 795696 0 1255925 9
Alaska 122640 0 164676 3
Arizona 1025232 0 1233654 11
Arkansas 394409 0 647744 6
California 7854285 55 4839958 0
Output:
Alabama 6356696 -37862896 6380 0
795696 6356696 -37862896 6380 0
0 6356696 -37862896 6380 0
1255925 6356696 -37862896 6380 0
9 6356696 -37862896 6380 0
Alaska 6356696 -37862896 6380 0
122640 6356696 -37862896 6380 0
0 6356696 -37862896 6380 0
164676 6356696 -37862896 6380 0
3 6356696 -37862896 6380 0
Arizona 6356696 -37862896 6380 0
1025232 6356696 -37862896 6380 0
0 6356696 -37862896 6380 0
1233654 6356696 -37862896 6380 0
11 6356696 -37862896 6380 0
Arkansas 6356696 -37862896 6380 0
394409 6356696 -37862896 6380 0
0 6356696 -37862896 6380 0
647744 6356696 -37862896 6380 0
6 6356696 -37862896 6380 0
California 6356696 -37862896 6380 0
7854285 6356696 -37862896 6380 0
55 6356696 -37862896 6380 0
4839958 6356696 -37862896 6380 0
0 6356696 -37862896 6380 0
Your scanf format string includes commas, but your input data does not.
Note that fscanf returns either EOF, or the number of values successfully scanned. You can and should use that return value to check for errors, and doing so would have pointed you to the problem in your code.
The commas in your fscanf format string tell fscanf to expect commas in the file and to stop if it does not find them.
There are no commas in your file, so fscanf stops after reading a “string” for the %s conversion.
Remove the commas from the format string.
Test that the return value of fscanf equals the number of items you expect to be assigned, not just that it is not equal to EOF.
Avoidable coding weakness lead to OP's difficulty
Had code checked the return value against the desired result of 5 rather than one of the many incorrect ones like EOF, 0, 1, 2, 3, 4, the issue would have been quickly narrowed to a scanf failure.
// while (fscanf(f, "%s, %ld, %ld, %ld, %ld", temp1, &temp2, &temp3, &temp4, &temp5) != EOF) {
while (fscanf(f, "%s, %ld, %ld, %ld, %ld", temp1, &temp2, &temp3, &temp4, &temp5) == 5) {
Other issues
White-space
No value, other than maybe style, to put a " " before "%ld" as "%ld" already consumes optional leading white-space.
Yet there is value to put a space before the "," to allow for optional leading white-space input before the ','.
while (fscanf(f, "%s ,%ld ,%ld ,%ld ,%ld", temp1, &temp2, &temp3, &temp4, &temp5) == 5) {
Buffer overflow
Never use "%s" in a (f)scanf() function. Use a width limit, else risk buffer overflow.
// width --------vv
while (fscanf(f, "%19s ,%ld ,%ld ,%ld ,%ld", temp1, &temp2, &temp3, &temp4, &temp5) == 5) {
fgetc() returns an int
fgetc(f) returns 257 different values. Use an int to correctly distinguish.
// char x;
int x;
...
while ((x = fgetc(f)) != EOF) {
Line count may fail
Count of lines only counted the number of '\n'. Had the file only contained "abc 1 2 3 4", with no '\n', the line count would report as 0.
Instead count the number of line beginnings.
count = 0;
int prior = '\n';
while ((x = fgetc(f)) != EOF) {
if (prior == '\n') {
count++;
}
prior = x;
...
}

a void function to fill the array by converting integer to binary

int main(void)
{
/* Stop WDT */
MAP_WDT_A_holdTimer();
/* Selecting P1.2 and P1.3 in UART mode */
MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
GPIO_PIN1 | GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);
/* Setting DCO to 12MHz */
CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12);
/* Configuring UART Module */
MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig);
/* Enable UART module */
MAP_UART_enableModule(EUSCI_A0_BASE);
/* Configuring GPIO2.4 as peripheral output for PWM and P6.7 for button
* interrupt */
MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2, GPIO_PIN4,
GPIO_PRIMARY_MODULE_FUNCTION);
redirect();
/* Configuring P1.0 as output */
MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);
/* Configuring Timer_A to have a period of approximately 500ms and
* an initial duty cycle of 10% of that (3200 ticks) */
//MAP_Interrupt_enableSleepOnIsrExit();
MAP_Interrupt_enableInterrupt(INT_TA0_0);
MAP_Timer_A_generatePWM(TIMER_A0_BASE,&pwmConfig);
MAP_Timer_A_clearInterruptFlag(TIMER_A0_BASE);
MAP_Timer_A_enableInterrupt(TIMER_A0_BASE);
MAP_Timer_A_enableCaptureCompareInterrupt
(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_0);
/* Enabling MASTER interrupts */
MAP_Interrupt_enableMaster();
/* Sleeping when not in use */
while (1)
{
//MAP_PCM_gotoLPM0();
}
}
const int bit_length = 33;
int period;
int times[33];
int values[32];
x=598;
number_bit=10;
// this function - period,times,values
// x is the 32 bit integer , number_bit is how many bits in that integer
void int_To_Arr(uint32_t x,int number_bit){
int i = 0;
period = BIT_LENGTH * 67 ; // 15fps -> 1/15=66.67m
for (i = 0; i < number_bit ; i++) {
if (((x >> i) & 1) == 0) /* shift right by i-bits, check on/off */
values[i] = 1000; /* assign to values[i] based on result */
else
values[i] = 11000;
times[i] = BIT_LENGTH * i; /* set times[i] */
}
times[i] = BIT_LENGTH * i;
}
void TA0_0_IRQHandler(void)
{
int i,value;
MAP_Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE,
TIMER_A_CAPTURECOMPARE_REGISTER_0);
time=time+1;
if(time>=period){
time=0;
MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
}
for(i=0;times[i]!=-1;i++){
if(times[i]>time){
break;
}
value=values[i];
}
MAP_Timer_A_setCompareValue(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1, value);
}
So this function will take x (32-bit integer) and number_bit(how many bits in the integer) and will fill the array in the main. if the bit is 1 , values = 11000 which will turn on the led. if the bit is 0 ,values =1000 .Unfortunately, the LED doesnt blink or do anything. Before this I do it manually, yes the LED blinking.
int time=0;
const int BIT_LENGTH = 33;
int period;
int times[33]; //{x}
int values[32];//{y}
//new 1001010110
const int period=667; //15fps - bitlength*67
const int times[]={0,67,200,267,333,400,467,600,667,-1};
const int values[]={11000,1000,11000,1000,11000,1000,11000,1000};
If through the extended discussions we have had, you are seeking to fill the values array based on the number_bits in the uint32_t x value passed to your int_to_array function by shifting the value x to the right number_bits times and at each iteration determining whether that bit in x is 0 or 1 and setting values[i] = 1000 if the bit is 0 and to 11000 if the bit is 1, then you could do something like the following:
#define BIT_LENGTH 33 /* if you need a constant, define one (or more) */
#define FPS_MULT 33
...
/* fill values based on nbits bit-values in x,
* fill times based on BIT_LENGTH and index.
* note: CHAR_BIT defined in limits.h
* (defined as 8 for virtually all common systems)
*/
void int_to_array (uint32_t x, int nbits)
{
int i = 0; /* loop variable - can be declared in loop for C99+ */
period = BIT_LENGTH * FPS_MULT; // your 30fps-1/30=0.033
/* validate nbits <= 32 */
if (nbits > (int)(sizeof x * CHAR_BIT)) {
fprintf (stderr, "error: nbits out of range of uint32_t\n");
return;
}
for (i = 0; i < nbits; i++) {
if (((x >> i) & 1) == 0) /* shift right by i-bits, check on/off */
values[i] = 1000; /* assign to values[i] based on result */
else
values[i] = 11000;
times[i] = BIT_LENGTH * i; /* set times[i] */
}
times[i] = BIT_LENGTH * i; /* final times[BIT_LENGTH - 1] */
}
While I am still unclear where those values come from, based on our discussion, that should be what you are looking for. Otherwise, I'm still uncertain. note I have added a validation check to insure nbits cannot exceed 32 (the number of bits in x)
Validation Test
If you wanted to write a short bit of validation code for your function, you could just write a short program that passes the value provided on the command line as the first argument to your function as x (nbits won't change, it will always be sizeof x * CHAR_BIT). The following code passes the first argument to the function (passing 10 by default if no argument is given on the command line)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <limits.h>
#define BIT_LENGTH 33 /* if you need a constant, define one (or more) */
#define FPS_MULT 33
int period;
int times[BIT_LENGTH];
int values[BIT_LENGTH - 1];
/* fill values based on nbits bit-values in x,
* fill times based on BIT_LENGTH and index.
* note: CHAR_BIT defined in limits.h
* (defined as 8 for virtually all common systems)
*/
void int_to_array (uint32_t x, int nbits)
{
int i = 0; /* loop variable - can be declared in loop for C99+ */
period = BIT_LENGTH * FPS_MULT; // your 30fps-1/30=0.033
/* validate nbits <= 32 */
if (nbits > (int)(sizeof x * CHAR_BIT)) {
fprintf (stderr, "error: nbits out of range of uint32_t\n");
return;
}
for (i = 0; i < nbits; i++) {
if (((x >> i) & 1) == 0) /* shift right by i-bits, check on/off */
values[i] = 1000; /* assign to values[i] based on result */
else
values[i] = 11000;
times[i] = BIT_LENGTH * i; /* set times[i] */
}
times[i] = BIT_LENGTH * i; /* final times[BIT_LENGTH - 1] */
}
int main (int argc, char **argv) {
unsigned long tmp = argc > 1 ? strtoul (argv[1], NULL, 0) : 10;
uint32_t x;
int i, nbits = sizeof x * CHAR_BIT;
if (errno || tmp > UINT32_MAX) {
fprintf (stderr, "error: conversion error or value out of range.\n");
return 1;
}
x = (uint32_t)tmp;
int_to_array (x, nbits);
printf ("x: %u\n\nperiod: %d\n\n", x, period);
for (i = 0; i < nbits; i++)
printf ("values[%2d]: %5d times[%2d]: %5d\n",
i, values[i], i, times[i]);
printf (" times[%2d]: %5d\n", i, times[i]);
return 0;
}
(note: I tweaked the function by addition optional parenthesis to a check to get rid of a -pedantic signed/unsigned comparison warning and added a final times[i] = BIT_LENGTH * i; after the loop to handle times having 1 more element than values)
Example Test
Simple default value of 10 (1010)
$ ./bin/values_times
x: 10
period: 1089
values[ 0]: 1000 times[ 0]: 0
values[ 1]: 11000 times[ 1]: 33
values[ 2]: 1000 times[ 2]: 66
values[ 3]: 11000 times[ 3]: 99
values[ 4]: 1000 times[ 4]: 132
values[ 5]: 1000 times[ 5]: 165
values[ 6]: 1000 times[ 6]: 198
values[ 7]: 1000 times[ 7]: 231
values[ 8]: 1000 times[ 8]: 264
values[ 9]: 1000 times[ 9]: 297
values[10]: 1000 times[10]: 330
values[11]: 1000 times[11]: 363
values[12]: 1000 times[12]: 396
values[13]: 1000 times[13]: 429
values[14]: 1000 times[14]: 462
values[15]: 1000 times[15]: 495
values[16]: 1000 times[16]: 528
values[17]: 1000 times[17]: 561
values[18]: 1000 times[18]: 594
values[19]: 1000 times[19]: 627
values[20]: 1000 times[20]: 660
values[21]: 1000 times[21]: 693
values[22]: 1000 times[22]: 726
values[23]: 1000 times[23]: 759
values[24]: 1000 times[24]: 792
values[25]: 1000 times[25]: 825
values[26]: 1000 times[26]: 858
values[27]: 1000 times[27]: 891
values[28]: 1000 times[28]: 924
values[29]: 1000 times[29]: 957
values[30]: 1000 times[30]: 990
values[31]: 1000 times[31]: 1023
times[32]: 1056
or a larger value, 0xdeadbeef (11011110101011011011111011101111)
$ ./bin/values_times 0xdeadbeef
x: 3735928559
period: 1089
values[ 0]: 11000 times[ 0]: 0
values[ 1]: 11000 times[ 1]: 33
values[ 2]: 11000 times[ 2]: 66
values[ 3]: 11000 times[ 3]: 99
values[ 4]: 1000 times[ 4]: 132
values[ 5]: 11000 times[ 5]: 165
values[ 6]: 11000 times[ 6]: 198
values[ 7]: 11000 times[ 7]: 231
values[ 8]: 1000 times[ 8]: 264
values[ 9]: 11000 times[ 9]: 297
values[10]: 11000 times[10]: 330
values[11]: 11000 times[11]: 363
values[12]: 11000 times[12]: 396
values[13]: 11000 times[13]: 429
values[14]: 1000 times[14]: 462
values[15]: 11000 times[15]: 495
values[16]: 11000 times[16]: 528
values[17]: 1000 times[17]: 561
values[18]: 11000 times[18]: 594
values[19]: 11000 times[19]: 627
values[20]: 1000 times[20]: 660
values[21]: 11000 times[21]: 693
values[22]: 1000 times[22]: 726
values[23]: 11000 times[23]: 759
values[24]: 1000 times[24]: 792
values[25]: 11000 times[25]: 825
values[26]: 11000 times[26]: 858
values[27]: 11000 times[27]: 891
values[28]: 11000 times[28]: 924
values[29]: 1000 times[29]: 957
values[30]: 11000 times[30]: 990
values[31]: 11000 times[31]: 1023
times[32]: 1056
Look things over and let me know if you have further questions.
It seems you want to examine each bit of x and see if it is 1 or 0, using >> is correct however doing
x>>i; //x<<i
if(x&1==0){
will not work because x>>i just returns what the value of x shifted i bits is, it does not update the value of x. Instead, I would do the following
x = x >> 1;
if(x&1==0){
It will shift the value of x by one each time through the loop and then check the rightmost bit.
Also, your loop counter is incorrect, instead of
for(i=1;i<x;i++){
You most likely want
for(i = 1; i < number_bit; i++) {
Actually looking at this again, you special case setting times[0] and values[0] outside the loop, and then start your loop at 1, so if you want to keep the code structured like that, your loop counter must be
for(i = 1; i < number_bit - 1; i++) {
Though looking at the code, I see no reason to special case the setting of times[0] and values[0], if you examine it closely, you'll see you can loop from
for(i = 0; i < number_bit; i++) {
and include setting times[0] and values[0] within the loop. You would just have to do the shift AFTER setting values or use an if to not shift x when i is 0.

coulomb's law force calculation using c code

I am trying to write a simple program in C to calculate pairwise interaction (Coulomb force) between two chain of beads.Both chains contain 10 beads but one chain is positively charged and the other one is negatively charged. I am reading the x,y,z coordinates and the charge information from two files (Charge from 7th column of atom.psf and coordinates from 6th 7th and 8th columns of beads.pdb).
Here are the contents of the files:
atom.psf
20 !NATOM
1 A 1 CHN A A 1.000000 0.0000 0
2 A 1 CHN A A 1.000000 0.0000 0
3 A 1 CHN A A 1.000000 0.0000 0
4 A 1 CHN A A 1.000000 0.0000 0
5 A 1 CHN A A 1.000000 0.0000 0
6 A 1 CHN A A 1.000000 0.0000 0
7 A 1 CHN A A 1.000000 0.0000 0
8 A 1 CHN A A 1.000000 0.0000 0
9 A 1 CHN A A 1.000000 0.0000 0
10 A 1 CHN A A 1.000000 0.0000 0
11 A 2 CHN A A -1.000000 0.0000 0
12 A 2 CHN A A -1.000000 0.0000 0
13 A 2 CHN A A -1.000000 0.0000 0
14 A 2 CHN A A -1.000000 0.0000 0
15 A 2 CHN A A -1.000000 0.0000 0
16 A 2 CHN A A -1.000000 0.0000 0
17 A 2 CHN A A -1.000000 0.0000 0
18 A 2 CHN A A -1.000000 0.0000 0
19 A 2 CHN A A -1.000000 0.0000 0
20 A 2 CHN A A -1.000000 0.0000 0
18 !NBOND: bonds
1 2 2 3 3 4 4 5
5 6 6 7 7 8 8 9
9 10 11 12 12 13 13 14
14 15 15 16 16 17 17 18
18 19 19 20
beads.pdb
ATOM 1 A CHN 1 1.000 0.000 0.000 1.00 0.00 A
ATOM 2 A CHN 1 2.000 0.000 0.000 1.00 0.00 A
ATOM 3 A CHN 1 3.000 0.000 0.000 1.00 0.00 A
ATOM 4 A CHN 1 4.000 0.000 0.000 1.00 0.00 A
ATOM 5 A CHN 1 5.000 0.000 0.000 1.00 0.00 A
ATOM 6 A CHN 1 6.000 0.000 0.000 1.00 0.00 A
ATOM 7 A CHN 1 7.000 0.000 0.000 1.00 0.00 A
ATOM 8 A CHN 1 8.000 0.000 0.000 1.00 0.00 A
ATOM 9 A CHN 1 9.000 0.000 0.000 1.00 0.00 A
ATOM 10 A CHN 1 10.000 0.000 0.000 1.00 0.00 A
ATOM 11 A CHN 2 1.000 80.000 0.000 1.00 0.00 A
ATOM 12 A CHN 2 2.000 80.000 0.000 1.00 0.00 A
ATOM 13 A CHN 2 3.000 80.000 0.000 1.00 0.00 A
ATOM 14 A CHN 2 4.000 80.000 0.000 1.00 0.00 A
ATOM 15 A CHN 2 5.000 80.000 0.000 1.00 0.00 A
ATOM 16 A CHN 2 6.000 80.000 0.000 1.00 0.00 A
ATOM 17 A CHN 2 7.000 80.000 0.000 1.00 0.00 A
ATOM 18 A CHN 2 8.000 80.000 0.000 1.00 0.00 A
ATOM 19 A CHN 2 9.000 80.000 0.000 1.00 0.00 A
ATOM 20 A CHN 2 10.000 80.000 0.000 1.00 0.00 A
I am having trouble with my final output. At every timestep (t=0 to 100), I need to write the coordinates of 20 atoms. My trial code is given below.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define Epsilon0 8.85e-12 // Permittivity of free space (C^2/(N m^2))
#define Constant (1/(4*M_PI*Epsilon0)) // Useful constant
#define gamma 100.0
#define ROW 20
int row, col, j, t;
float x[20], y[20], z[20], q[20], dx, dy, dz, R, Fx, Fy, Fz, F, v, shift;
int main()
{
FILE *psf=fopen("atom.psf", "r");
FILE *pdb=fopen("beads.pdb", "r");
FILE *fout=fopen("out.txt", "a");
FILE *fout2=fopen("coord.dump", "a");
fprintf(fout2, "ITEM: TIMESTEP\n 100\n");
fprintf(fout2, "ITEM: NUMBER OF ATOMS\n 20\n");
fprintf(fout2, "ITEM: ATOMS id type x y z\n");
char buffer[1024];
fgets(buffer, 1024, psf);
int i = 0;
for(i=0 ; (i<ROW) && (psf != NULL); i++)
{
fscanf (psf,"%*8d%*4s%*4d%*6s%*5s%*6s%11f%*14f%*12d", &q[i]);
fscanf (pdb,"%*4s%*7d%*5s%*4s%*6d%12f%8f%8f%*6f%*6f%*9s", &x[i], &y[i], &z[i]);
}
for (t=0; t<100; t++)
{
//F = 0.0;
v = F/gamma;
shift = v*t;
x[i] = x[i] + shift;
y[i] = y[i] + shift;
z[i] = z[i] + shift;
for(i=0; i<ROW; i++)
{
Fx = Fy = Fz = F = 0.0;
// Loop over other charges to compute force on this charge
for (j=0 ; j<ROW ; j++)
{
//simply skip this itearation
if(i == j)
continue;
// Compute the components of vector distance between two charges
dx = x[i] - x[j];
dy = y[i] - y[j];
dz = z[i] - z[j];
R = sqrt(dx*dx + dy*dy + dz*dz);
// Compute the x and y components of the force between
// these two charges using Coulomb's law
Fx += Constant*q[i]*q[j]*dx/(R*R*R);
Fy += Constant*q[i]*q[j]*dy/(R*R*R);
Fz += Constant*q[i]*q[j]*dz/(R*R*R);
}
F = sqrt(Fx*Fx + Fy*Fy + Fz*Fz);
fprintf(fout, "%d %3.3g %3.3g %3.3g %3.3g\n", i+1, Fx, Fy, Fz, F);
//fprintf(fout2, "%d %3.3g %3.3g %3.3g\n", i+1, x[i], y[i], z[i]);
}
fprintf(fout2, "%d %3.3g %3.3g %3.3g\n", i, x[i], y[i], z[i]);
}
}
This is probably a situation where instead of attempting to keep track of numerous separate arrays containing various information, life can be made a lot easier if you simply create a struct that captures the needed information for each bead and then create a single array of struct. For example, you want to capture the x,y,z position, charge, and component forces acting on each bead. (I included the total force as well, but that is optional). Your struct for each bead (I called it beads) could be as simple as:
typedef struct {
float x, y, z, chrg, fx, fy, fz, f;
} beads;
In your code, you simply create an array of beads (one for each bead you need information on). For example, creating an array of beads with 20 elements, you could do something like the following:
#define Eo 8.85e-12F
#define KEair (1/(4*M_PI*Eo))
enum { NATM = 20, MAXL = 128 }; /* constants for number of beads/line len */
...
beads atoms[NATM] = {{ .x = 0.0 }};
Now we have an array of struct called atoms to store information in. You can read information from each of your files and store the x, y, z positions for each bead as well as the charge. Then you can compute the force acting on each bead by computing the force due to every other bead and summing the information in the remaining force component and total members of each struct. You may do something like:
for (i = 0; i < NATM; i++) { /* for each bead */
for (size_t j = 0; j < NATM; j++) { /* compute force from every other */
if (i == j) continue; /* excluding itself */
float dx = atoms[j].x - atoms[i].x, /* calculate component distances */
dy = atoms[j].y - atoms[i].y,
dz = atoms[j].z - atoms[i].z,
d = sqrt (dx * dx + dy * dy + dz * dz); /* total distance */
/* compute component and total forces acting on each bead (sum) */
atoms[i].fx += (KEair * atoms[i].chrg *atoms[j].chrg * dx)/(d * d * d);
atoms[i].fy += (KEair * atoms[i].chrg *atoms[j].chrg * dy)/(d * d * d);
atoms[i].fz += (KEair * atoms[i].chrg *atoms[j].chrg * dz)/(d * d * d);
atoms[i].f += (KEair * atoms[i].chrg *atoms[j].chrg)/(d * d);
}
}
(you can confirm the approach to the sum at System of discrete charges)
Putting it altogether, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define Eo 8.85e-12F
#define KEair (1/(4*M_PI*Eo))
enum { NATM = 20, MAXL = 128 };
typedef struct {
float x, y, z, chrg, fx, fy, fz, f;
} beads;
FILE *xfopen (const char *fn, const char *mode);
float sqrt_fisr (float x);
int main (int argc, char **argv) {
beads atoms[NATM] = {{ .x = 0.0 }};
size_t i;
char buf[MAXL] = ""; /* open/read atom.psf */
FILE *fp = xfopen (argc > 1 ? argv[1] : "dat/atom.psf", "r");
fgets (buf, MAXL, fp); /* read/discard 1st line */
for (i = 0; i < NATM && fgets (buf, MAXL, fp); i++) { /* read/parse data */
if (sscanf (buf, "%*s %*s %*s %*s %*s %*s %f", &atoms[i].chrg) != 1) {
fprintf (stderr, "error: read of charge failed, atom[%zu].\n", i);
return 1;
}
}
fclose (fp);
if (i != NATM) { /* validate NATM lines read */
fprintf (stderr, "error: only '%zu' charge values read.\n", i);
return 1;
}
/* open/read beads.pdb */
fp = xfopen (argc > 2 ? argv[2] : "dat/beads.pdb", "r");
for (i = 0; i < NATM && fgets (buf, MAXL, fp); i++) { /* read/parse data */
if (sscanf (buf, "%*s %*s %*s %*s %*s %f %f %f", &atoms[i].x,
&atoms[i].y, &atoms[i].z) != 3) {
fprintf (stderr, "error: read of position failed, atom[%zu].\n", i);
return 1;
}
}
fclose (fp);
if (i != NATM) { /* validate NATM lines read */
fprintf (stderr, "error: only '%zu' position values read.\n", i);
return 1;
}
for (i = 0; i < NATM; i++) { /* for each bead */
for (size_t j = 0; j < NATM; j++) { /* compute force from every other */
if (i == j) continue; /* excluding itself */
float dx = atoms[j].x - atoms[i].x, /* calculate component distances */
dy = atoms[j].y - atoms[i].y,
dz = atoms[j].z - atoms[i].z,
d = sqrt (dx * dx + dy * dy + dz * dz); /* total distance */
/* compute component and total forces acting on each bead (sum) */
atoms[i].fx += (KEair * atoms[i].chrg *atoms[j].chrg * dx)/(d * d * d);
atoms[i].fy += (KEair * atoms[i].chrg *atoms[j].chrg * dy)/(d * d * d);
atoms[i].fz += (KEair * atoms[i].chrg *atoms[j].chrg * dz)/(d * d * d);
atoms[i].f += (KEair * atoms[i].chrg *atoms[j].chrg)/(d * d);
}
}
for (i = 0; i < NATM; i++) /* output forces on each bead (component and total) */
printf (" atom[%2zu] %5.2f %5.2f %5.2f %+.2f %15.2f %15.2f %5.2f %15.2f\n",
i, atoms[i].x, atoms[i].y, atoms[i].z, atoms[i].chrg,
atoms[i].fx, atoms[i].fy, atoms[i].fz, atoms[i].f);
return 0;
}
/** simple fopen with error check */
FILE *xfopen (const char *fn, const char *mode)
{
FILE *fp = fopen (fn, mode);
if (!fp) {
fprintf (stderr, "xfopen() error: file open failed '%s'.\n", fn);
exit (EXIT_FAILURE);
}
return fp;
}
Example Use/Output
$ ./bin/coulomb
atom[ 0] 1.00 0.00 0.00 +1.00 13844509696.00 -13956823.00 0.00 13831302144.00
atom[ 1] 2.00 0.00 0.00 +1.00 4741866496.00 -13982750.00 0.00 22712082432.00
atom[ 2] 3.00 0.00 0.00 +1.00 2353591552.00 -14002249.00 0.00 24819521536.00
atom[ 3] 4.00 0.00 0.00 +1.00 1171170304.00 -14015272.00 0.00 25635096576.00
atom[ 4] 5.00 0.00 0.00 +1.00 359584800.00 -14021791.00 0.00 25947308032.00
atom[ 5] 6.00 0.00 0.00 +1.00 -359584608.00 -14021791.00 0.00 25947308032.00
atom[ 6] 7.00 0.00 0.00 +1.00 -1171170944.00 -14015272.00 0.00 25635096576.00
atom[ 7] 8.00 0.00 0.00 +1.00 -2353592320.00 -14002249.00 0.00 24819521536.00
atom[ 8] 9.00 0.00 0.00 +1.00 -4741866496.00 -13982751.00 0.00 22712082432.00
atom[ 9] 10.00 0.00 0.00 +1.00 -13844510720.00 -13956824.00 0.00 13831303168.00
atom[10] 1.00 80.00 0.00 -1.00 13844507648.00 13956823.00 0.00 13831302144.00
atom[11] 2.00 80.00 0.00 -1.00 4741867008.00 13982750.00 0.00 22712080384.00
atom[12] 3.00 80.00 0.00 -1.00 2353592064.00 14002249.00 0.00 24819521536.00
atom[13] 4.00 80.00 0.00 -1.00 1171170944.00 14015272.00 0.00 25635096576.00
atom[14] 5.00 80.00 0.00 -1.00 359585056.00 14021791.00 0.00 25947308032.00
atom[15] 6.00 80.00 0.00 -1.00 -359584864.00 14021791.00 0.00 25947308032.00
atom[16] 7.00 80.00 0.00 -1.00 -1171170560.00 14015272.00 0.00 25635096576.00
atom[17] 8.00 80.00 0.00 -1.00 -2353591808.00 14002249.00 0.00 24819521536.00
atom[18] 9.00 80.00 0.00 -1.00 -4741867008.00 13982751.00 0.00 22712080384.00
atom[19] 10.00 80.00 0.00 -1.00 -13844509696.00 13956824.00 0.00 13831304192.00
Looking at the output graphically, the forces increase from the end to a maximum in the center of each string or beads -- that checks, and the forces acting upon the beads in the X-direction is the greatest at each end and reverses direction at midpoint -- also a check. For example:
Total Force Acting on Each Bead
Forces acting in the X direction on Each Bead
Look things over and let me know if you have any questions.
Here's what I would change in your code:
Epsilon and Constant should be declared as constants:
"#define Epsilon0 8.85e-12"
"#define Constant (1/(4*pi*Epsilon0))""
Move the "i != j" inside the loop. That would prevent the loop from stopping if you hit that condition. You would just be skipping that iteration instead of stopping completely.
You don't really need the xi, yi , zij, Fx, Fy, Fz, Rij arrays. You can use simple variables as placeholders instead.
During each iteration of the inner loop, you would be calculating the partial force du to bead j. You need to add that force to the cumulative force.
In order to do that you can declare Fx, Fy and Fz outside of the loops, initialize the 3 variable to 0 inside the first loop and then add partial forces inside the inner loop.
Move the fprintf outside of the inner loop (but keep it inside the external loop)
UPDATE
This code does not handle I/O errors
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define Epsilon0 8.85e-12 // Permittivity of free space (C^2/(N m^2))
#define Constant (1/(4*M_PI*Epsilon0)) // Useful constant
#define ROW 20
int row, col, j;
float x[20], y[20], z[20], q[20], dx, dy, dz, R, Fx, Fy, Fz, F;
int main()
{
FILE *psf=fopen("atom.psf", "r");
FILE *pdb=fopen("beads.pdb", "r");
FILE *fout=fopen("out.txt", "w");
char buffer[1024];
fgets(buffer, 1024, psf);
int i = 0;
for( ; (i<ROW) && (psf != NULL); i++)
{
fscanf (psf,"%*8d%*4s%*4d%*6s%*5s%*6s%11f%*14f%*12d", &q[i]);
fscanf (pdb,"%*4s%*7d%*5s%*4s%*6d%12f%8f%8f%*6f%*6f%*9s", &x[i], &y[i], &z[i]);
}
for(i=0; i<ROW; i++)
{
Fx = Fy = Fz = F = 0.0;
// Loop over other charges to compute force on this charge
for (j=0 ; j<ROW ; j++)
{
//simply skip this itearation
if(i == j)
continue;
// Compute the components of vector distance between two charges
dx = x[i] - x[j];
dy = y[i] - y[j];
dz = z[i] - z[j];
R = sqrt(dx*dx + dy*dy + dz*dz);
// Compute the x and y components of the force between
// these two charges using Coulomb's law
Fx += Constant*q[i]*q[j]*dx/(R*R*R);
Fy += Constant*q[i]*q[j]*dy/(R*R*R);
Fz += Constant*q[i]*q[j]*dz/(R*R*R);
}
F = sqrt(Fx*Fx + Fy*Fy + Fz*Fz);
fprintf(fout, "%d %g %g %g, %g\n", i+1, Fx, Fy, Fz, F);
}
}
Something that may help
The for loop,
`for (j = 0; j<ROW && i != j; j++)`
Will exit when i == j as the loop condition is false. For example when i is 1 will only iterate through the loop once, when j is 0.
Use if statement inside the for loop to skip the current charge, i.e when i == j
for (j = 0; j<ROW ; j++)
{
if (i != j)
{
DO CALCULATION... `
Also, think that Fx[i] will only ever have store the force due to an single j charge as it is assignment for each iteration rather than a sum.
Consider changing to accumlate for each interation, i.e. Fx[i] += then calculate F[i] when this for loop has completed

Scanf stops working abruptly

I'm trying to read data from an stl file, one character at a time using scanf/fscanf. I call scanf many times in my program, but input all the data at the first instance. It works perfectly for a while, but it seems like as soon as scanf is called the 1022nd or 1023rd time, the program stops and prompts for more input, even though there is plenty left to scan.
I've written a program before that called scanf more than 40,000 times on one input, so I don't know what the deal is...
It seems to stop working at the first scanf in getnormal() when z == 7;
#include <stdio.h>
#include <stdlib.h>
void getnormal(char[], double[]);
void getvertices(char[], double[], int);
int main (int argc, char *argv[]) {
unsigned char trash = 0;
int z = 0;
char num[20];
for (int i = 0; i < 20; i++)
num[i] = 48;
double normal [3] = {0,0,0};
double vertices [9] = {0,0,0,0,0,0,0,0,0};
//FILE *in = fopen(argv[1], "r");
//FILE *out = fopen(argv[2], "w");
while (trash != '\n')
scanf("%c", &trash);
while (1) {
getnormal(num, normal);
for (int i = 1; i <= 3; i++)
getvertices(num, vertices, i);
z++;
}
}
double getnumber(char num[]) {
unsigned char trash = 0;
for (int i = 0; i < 20; i++)
num[i] = 48;
scanf("%c", &trash);
for (int j = 0; trash != ' ' && trash != '\n'; j++) {
num[j] = trash;
scanf("%c", &trash);
if (trash == 'e') {
for (int h = 0; h < 4; h++)
scanf("%c", &trash);
break;
}
}
return atof(num);
}
void getnormal(char num[], double normal[]) {
unsigned char trash = 0;
while (trash != 'm')
scanf("%c", &trash);
while (trash != 'l')
scanf("%c", &trash);
scanf("%c", &trash);
for (int i = 0; i < 3; i++)
normal[i] = getnumber(num);
printf("\nnormal:");
for (int i = 0; i < 3; i++)
printf(" %f", normal[i]);
printf("\n");
}
void getvertices(char num[], double vertices[], int vertex) {
unsigned char trash = 0;
vertex = (vertex-1) * 3;
while (trash != 'x')
scanf("%c", &trash);
scanf("%c", &trash);
for (int i = 0; i < 3; i++)
vertices[vertex+i] = getnumber(num);
printf("vertex:");
for (int i = 0; i < 3; i++) {
printf(" %f", vertices[vertex+i]);
}
printf("\n");
}
Here's the input:
solid Untitled-56807ca1
facet normal 0.0 0.0 -1.0
outer loop
vertex 100.0 50.0 0.0
vertex 0.0 0.0 0.0
vertex 0.0 50.0 0.0
endloop
endfacet
facet normal 0.0 0.0 -1.0
outer loop
vertex 0.0 0.0 0.0
vertex 100.0 50.0 0.0
vertex 100.0 0.0 0.0
endloop
endfacet
facet normal -1.0 0.0 0.0
outer loop
vertex 0.0 50.0 67.80499999999999
vertex 0.0 0.0 0.0
vertex 0.0 0.0 67.80499999999999
endloop
endfacet
facet normal -1.0 0.0 0.0
outer loop
vertex 0.0 0.0 0.0
vertex 0.0 50.0 67.80499999999999
vertex 0.0 50.0 0.0
endloop
endfacet
facet normal -0.0 1.0 0.0
outer loop
vertex 0.0 50.0 67.80499999999999
vertex 100.0 50.0 0.0
vertex 0.0 50.0 0.0
endloop
endfacet
facet normal -0.0 1.0 0.0
outer loop
vertex 100.0 50.0 0.0
vertex 0.0 50.0 67.80499999999999
vertex 100.0 50.0 67.80499999999999
endloop
endfacet
facet normal 1.0 0.0 0.0
outer loop
vertex 100.0 50.0 0.0
vertex 100.0 0.0 67.80499999999999
vertex 100.0 0.0 0.0
endloop
endfacet
facet normal 1.0 0.0 0.0
outer loop
vertex 100.0 0.0 67.80499999999999
vertex 100.0 50.0 0.0
vertex 100.0 50.0 67.80499999999999
endloop
endfacet
facet normal -0.0 -1.0 -0.0
outer loop
vertex 100.0 0.0 67.80499999999999
vertex 0.0 0.0 0.0
vertex 100.0 0.0 0.0
endloop
endfacet
facet normal -0.0 -1.0 -0.0
outer loop
vertex 0.0 0.0 0.0
vertex 100.0 0.0 67.80499999999999
vertex 0.0 0.0 67.80499999999999
endloop
endfacet
facet normal 0.8393626319551987 8.038371845750061e-18 0.5435718646851044
outer loop
vertex 100.0 50.0 67.80499999999999
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 100.0 0.0 67.80499999999999
endloop
endfacet
facet normal 0.8393626319551987 8.038371845750061e-18 0.5435718646851044
outer loop
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 100.0 50.0 67.80499999999999
vertex 68.99999999999989 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal -0.8393626319552003 -1.4889432537737797e-17 0.5435718646851019
outer loop
vertex 30.9999999999999 15.49999999999995 115.67399999999996
vertex 0.0 50.0 67.80499999999999
vertex 0.0 0.0 67.80499999999999
endloop
endfacet
facet normal -0.8393626319552003 -1.4889432537737797e-17 0.5435718646851019
outer loop
vertex 0.0 50.0 67.80499999999999
vertex 30.9999999999999 15.49999999999995 115.67399999999996
vertex 30.9999999999999 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal -5.5971483140148576e-18 -0.9513689920122365 0.30805363337837904
outer loop
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 0.0 0.0 67.80499999999999
vertex 100.0 0.0 67.80499999999999
endloop
endfacet
facet normal -5.5971483140148576e-18 -0.9513689920122365 0.30805363337837904
outer loop
vertex 0.0 0.0 67.80499999999999
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 30.9999999999999 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal 9.646494768713815e-18 0.9513689920122359 0.30805363337838126
outer loop
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 100.0 50.0 67.80499999999999
vertex 0.0 50.0 67.80499999999999
endloop
endfacet
facet normal 9.646494768713815e-18 0.9513689920122359 0.30805363337838126
outer loop
vertex 100.0 50.0 67.80499999999999
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 68.99999999999989 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal 0.0 -0.8819736246769688 0.47129876445219904
outer loop
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 30.9999999999999 15.49999999999995 115.67399999999996
vertex 68.99999999999989 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal 0.6832351395351168 5.963605871623595e-18 0.7301984278978073
outer loop
vertex 68.99999999999989 34.49999999999993 115.67399999999996
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 68.99999999999989 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal -0.6832351395351168 5.963605871623845e-18 0.7301984278978073
outer loop
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 30.9999999999999 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal -0.0 -0.0 1.0
outer loop
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 30.9999999999999 15.49999999999995 115.67399999999996
endloop
endfacet
facet normal -0.0 -0.0 1.0
outer loop
vertex 30.9999999999999 34.49999999999993 115.67399999999996
vertex 68.99999999999989 15.49999999999995 115.67399999999996
vertex 68.99999999999989 34.49999999999993 115.67399999999996
endloop
endfacet
facet normal -0.0 0.8819736246769686 0.47129876445219915
outer loop
vertex 49.99999999999989 24.99999999999994 133.45199999999997
vertex 68.99999999999989 34.49999999999993 115.67399999999996
vertex 30.9999999999999 34.49999999999993 115.67399999999996
endloop
endfacet
endsolid Untitled-56807ca1
Here's the output:
normal: 0.000000 0.000000 -1.000000
vertex: 100.000000 50.000000 0.000000
vertex: 0.000000 0.000000 0.000000
vertex: 0.000000 50.000000 0.000000
normal: 0.000000 0.000000 -1.000000
vertex: 0.000000 0.000000 0.000000
vertex: 100.000000 50.000000 0.000000
vertex: 100.000000 0.000000 0.000000
normal: -1.000000 0.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 0.000000 0.000000 0.000000
vertex: 0.000000 0.000000 67.805000
normal: -1.000000 0.000000 0.000000
vertex: 0.000000 0.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 0.000000 50.000000 0.000000
normal: -0.000000 1.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 100.000000 50.000000 0.000000
vertex: 0.000000 50.000000 0.000000
normal: -0.000000 1.000000 0.000000
vertex: 100.000000 50.000000 0.000000
vertex: 0.000000 50.000000 67.805000
vertex: 100.000000 50.000000 67.805000
normal: 1.000000 0.000000 0.000000
vertex: 100.000000 50.000000 0.000000
vertex: 100.000000 0.000000 67.805000
vertex: 100.000000 0.000000 0.000000
When you get into handling text files containing more than the basic "each line holds the same information", you are better served utilizing line-oriented input functions like fgets or getline in order to separate 'reading' of your data and 'processing (or parsing)' of your data that too often people attempt to shoehorn into a scanf format string that results in more grief than good.
As mentioned in my comment, when all the input lines are guaranteed to hold the same type and number of variables, and in the exact same format on every line, then the scanf family of input functions can be used fairly reliably. But when your data varies line-by-line, reading each line into a buffer and then having the luxury of writing a handler to parse and validate what was read will result in a far more robust code.
Before beginning your reading, you must decide on how you will hold your values in memory. Whether in a struct, an array, a combination? While C is flexible enough to allow you wide latitude in how you store your data, a bit of thinking up-front on what parts of your data are relatively fixed and what parts will continue to grow, can help you sort out a reasonable storage scheme.
In your case, the data you need that is relatively fixed in size is the name (or label) for your solid (e.g. Untitled-56807ca1 in your sample data). The number of normal/vertex sets can be a single number, and keeping track of the max number you can store is also a single number.
The data that will grow as you read from your input file will be the values for the facet normal arrays and the vertex arrays. Here you will need some way of reading as many as are contained in the file (likely without knowing how many are there when you start). Of course, if you do not need to store the data, but simply use the values as they are read, this isn't a concern, but in most cases, you want to be able to store your data so it can be passed to other parts of your code where it can be used.
While you can do it a number of ways, a nested struct, where the fixed values are members of the outer, or base, struct, which also holds a pointer to your data (or nested struct of normal and vertex arrays makes sense. You can make life easier with a simple create or initialization function that allocates and initializes the structs and their values each time a new named solid is read.
After setting up how you will hold/store your data, it is then just a matter of reading each line, examining/parsing the line contents, and taking the appropriate actions based on what you find in each line. You should also make sure you get what you expect to find in each line, and warn or throw an error if your code reads a line it doesn't understand.
There is no better way to put these pieces together than in a short example to read your posted input file so you can get a flavor for it. Note: there are many ways to do this in C, all with their advantages/disadvantages, this is just one for you to consider and to ask questions about to help your understand how a line-oriented approach may benefit what you are attempting to do. Look over the example and let me know what questions you have:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h> /* for ERANGE and errno */
#include <math.h> /* for HUGE_VALF, HUGE_VALL */
/* constants - num dimensions, initial facets
* allocated within each solid, and the max
* chars per-line for fgets to read
*/
enum { NDIM = 3, FACETS = 32, MAXC = 256 };
/* facets struct - declared as pointer member of
* struct solid allowing additional allocation to
* hold as many normal/vertexes as required.
*/
typedef struct {
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 {
char *name;
facet *facet;
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);
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) {
/* reallocate (*sol)->facets here,
* update (*sol)->maxfacets to new size
*/
fprintf (stderr, "read_solid() warning: limit reached\n"
"you must reallocate or increase FACETS\n");
break;
}
}
goto processed;
}
if (strncmp ("solid", line, ep - p) == 0)
{ /* begins with 'solid', set 'name' */
(*sol)->name = strdup (ep + 1);
goto processed;
}
else if (strncmp ("facet", line, ep - p) == 0)
{ /* read facet normal values */
size_t i;
while (*ep && (*ep < '0' || *ep > '9')) ep++;
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 */
(*sol)->facet[(*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)->facet[(*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) {
goto processed;
}
else if (strncmp ("endsolid", line, ep - p) == 0) {
goto processed;
}
else { /* if any line not processed - warn of unrecognized line */
fprintf (stderr, "read_solid() warning: invalid line at '%zu'\n", idx);
}
processed:
idx++; /* update line index */
}
if (!(*sol)->nfacets) { /* if no facet data, free mem, return NULL */
fprintf (stderr, "read_solid() error: no data read.\n");
free_solid (*sol);
return NULL;
}
return *sol;
}
/* simple allocate/initialize function
* return must be assigned to pointer
*/
solid *create_solid ()
{
size_t i;
solid *sol = calloc (1, sizeof *sol);
sol->facet = calloc (FACETS, sizeof *(sol->facet));
sol->nfacets = 0;
sol->maxfacets = FACETS;
for (i = 0; i < FACETS; i++) {
memset ((sol->facet)[i].normal, 0, NDIM * sizeof (double));
memset ((sol->facet)[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, "print_solid() error: invalid parameter 'sol'.\n");
return;
}
size_t n, i;
printf ("\nnormal and vertexes for solid: %s\n", sol->name);
for (n = 0; n < sol->nfacets; n++) {
printf ("\n normal[%3zu] : %10.4f %10.4f %10.4f\n", n,
sol->facet[n].normal[0],
sol->facet[n].normal[1],
sol->facet[n].normal[2]);
for (i = 0; i < NDIM; i++)
printf (" vertex[%2zu] : %10.4f %10.4f %10.4f\n", i,
sol->facet[n].vertex[i][0],
sol->facet[n].vertex[i][1],
sol->facet[n].vertex[i][2]);
}
}
/* free allocated memory */
void free_solid (solid *sol)
{
if (sol->name) free (sol->name);
if (sol->facet) free (sol->facet);
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 digits were found\n");
exit (EXIT_FAILURE);
}
return val;
}
Compile (gcc)
gcc -Wall -Wextra -O3 -o bin/readsolid readsolid.c
Use/Output
$ ./bin/readsolid dat/solid.txt
normal and vertexes for solid: Untitled-56807ca1
normal[ 0] : 0.0000 0.0000 -1.0000
vertex[ 0] : 100.0000 50.0000 0.0000
vertex[ 1] : 0.0000 0.0000 0.0000
vertex[ 2] : 0.0000 50.0000 0.0000
normal[ 1] : 0.0000 0.0000 -1.0000
vertex[ 0] : 0.0000 0.0000 0.0000
vertex[ 1] : 100.0000 50.0000 0.0000
vertex[ 2] : 100.0000 0.0000 0.0000
normal[ 2] : 1.0000 0.0000 0.0000
vertex[ 0] : 0.0000 50.0000 67.8050
vertex[ 1] : 0.0000 0.0000 0.0000
vertex[ 2] : 0.0000 0.0000 67.8050
normal[ 3] : 1.0000 0.0000 0.0000
vertex[ 0] : 0.0000 0.0000 0.0000
vertex[ 1] : 0.0000 50.0000 67.8050
vertex[ 2] : 0.0000 50.0000 0.0000
normal[ 4] : 0.0000 1.0000 0.0000
vertex[ 0] : 0.0000 50.0000 67.8050
vertex[ 1] : 100.0000 50.0000 0.0000
vertex[ 2] : 0.0000 50.0000 0.0000
<snip>
normal[ 21] : 0.0000 -0.0000 1.0000
vertex[ 0] : 69.0000 15.5000 115.6740
vertex[ 1] : 31.0000 34.5000 115.6740
vertex[ 2] : 31.0000 15.5000 115.6740
normal[ 22] : 0.0000 -0.0000 1.0000
vertex[ 0] : 31.0000 34.5000 115.6740
vertex[ 1] : 69.0000 15.5000 115.6740
vertex[ 2] : 69.0000 34.5000 115.6740
normal[ 23] : 0.0000 0.8820 0.4713
vertex[ 0] : 50.0000 25.0000 133.4520
vertex[ 1] : 69.0000 34.5000 115.6740
vertex[ 2] : 31.0000 34.5000 115.6740
Memory/Error Check
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory and to confirm that you have freed all the memory you have allocated.
For Linux valgrind is the normal choice. There are so many subtle ways to misuse a block of memory that can cause real problems, there is no excuse not to do it. There are similar memory checkers for every platform. They are all simple to use. Just run your program through it.
$ valgrind ./bin/readsolid dat/solid.txt
==4651== Memcheck, a memory error detector
==4651== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==4651== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==4651== Command: ./bin/readsolid dat/solid.txt
==4651==
normal and vertexes for solid: Untitled-56807ca1
normal[ 0] : 0.0000 0.0000 -1.0000
vertex[ 0] : 100.0000 50.0000 0.0000
vertex[ 1] : 0.0000 0.0000 0.0000
vertex[ 2] : 0.0000 50.0000 0.0000
<snip>
==4651==
==4651== HEAP SUMMARY:
==4651== in use at exit: 0 bytes in 0 blocks
==4651== total heap usage: 4 allocs, 4 frees, 3,690 bytes allocated
==4651==
==4651== All heap blocks were freed -- no leaks are possible
==4651==
==4651== For counts of detected and suppressed errors, rerun with: -v
==4651== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Note: this example ended up longer than I originally envisioned, but to provide adequate validation for any relatively sophisticated set of data, it will take a little bit of code to get it done correctly. Good luck.
Your function getnumber has several problems:
The buffer num is initialized to all '0' without a null terminator. You patch some bytes into it until you see a space or a linefeed and call atof.
There is no test to prevent buffer overflow, invalid input may well cause that at some point in the input file.
The buffer is not null terminated. atof will stop on the first character that does not match the floating point syntax, but if all positions are digits, it will keep reading past the end of the num array.
The whole code is very cumbersome and the semantics are unclear.
You never test the return value from scanf: upon end of file, the contents of the unsigned char whose address is passed as argument to scanf will be indeterminate, most likely untouched from the previous value... potentially causing buffer overflow in getnumber as well.
There is no way for your program to break from the while (1) loop. Sooner or later, you will reach the end of file and your code will either invoke undefined behavior or get stuck in an infinite loop.
Rewrite your code with getchar() or fgets and properly check for end of file.

Read numbers from text file to 2D array

Despite the numerous examples on here I can't seem to get this working...
I have a text file, containing many rows, each row has three (int) values separated by a single space. For example:
1 0 0
0 0 0
1 0 1
0 0 2
1 0 2
I am trying to read this into a 2d array.
My code so far:
int main(void)
{
char c;
int i = 0;
int maxLines = 18;
char lines[maxLines][BUFSIZ];
FILE *fp = fopen("inputs/control.txt", "r");
if (fp == 0)
{
fprintf(stderr, "failed to open inputs/control.txt\n");
exit(1);
}
char buffer[maxLines];
while (i < maxLines && fgets(buffer[i], sizeof(buffer[0]), fp))
{
sscanf (buffer, "%d %d %d", &lines[i][0], &lines[i][1], &lines[i][2]);
i++;
}
fclose(fp);
return 0;
}
Can someone provide advice how I can develop this further so that each value in the row is stored in a separate array index? In my example above, we would store something like:
lines[0][0] = 1
lines[0][1] = 0
lines[0][2] = 0
and so on.....
Currently it stores the entire row in a single array pos.
As you can probably tell I'm a C noob, any help would be fantastic!
You were well on your way, you just had problems thinking you were reading a character array instead of an array of signed characters (which could be changed to int, etc) Here is your example:
#include <stdio.h>
#define MAXB 32
#define MAXL 18
#define MAXD 3
int main(void)
{
int i = 0;
int numlines = 0;
char buf[MAXB] = {0};
char lines[MAXL][MAXD];
FILE *fp = fopen("inputs/control.txt", "r");
if (fp == 0)
{
fprintf(stderr, "failed to open inputs/control.txt\n");
return 1;
}
while (i < MAXL && fgets (buf, MAXB - 1, fp))
{
if (sscanf (buf, "%hhd %hhd %hhd", &lines[i][0], &lines[i][1], &lines[i][2]) == 3)
i++;
}
fclose(fp);
numlines = i;
int j = 0;
for (i = 0; i < numlines; i++)
for (j = 0; j < MAXD; j++)
printf (" line[%2d][%2d] : %hhd\n", i, j, lines[i][j]);
printf ("\n");
return 0;
}
Output
$ ./bin/read_array_a3
line[ 0][ 0] : 1
line[ 0][ 1] : 0
line[ 0][ 2] : 0
line[ 1][ 0] : 0
line[ 1][ 1] : 0
line[ 1][ 2] : 0
line[ 2][ 0] : 1
line[ 2][ 1] : 0
line[ 2][ 2] : 1
line[ 3][ 0] : 0
line[ 3][ 1] : 0
line[ 3][ 2] : 2
line[ 4][ 0] : 1
line[ 4][ 1] : 0
line[ 4][ 2] : 2
Note: char lines[MAXL][MAXD]; is fine, you just must understand that each element is restricted to an 8-bit signed value, meaning values between -128 < val < 127. You can make them int if you need to store larger values.
Use scanf. Example:
#include <stdio.h>
int main(int argc, char *argv[]) {
int i, j;
int lines[18][3];
i = 0;
while (
i != sizeof(lines) / sizeof(lines[0])
&& 3 == scanf("%i %i %i", lines[i] + 0, lines[i] + 1, lines[i] + 2)
) {
i++;
}
for (j = 0; j !=i; j++) {
printf("%i %i %i\n", lines[j][0], lines[j][1], lines[j][2]);
}
return 0;
}
Note that the input is read from stdin (use fscanf for more flexibility), meaning that the snippet above must be called as ./a.out < data.txt.
Using fgets you are reading the whole line from the file. You will need to then parse this line to extract individual numbers and store them into the array. In the while loop you can read the line in a buffer and then use something like strtok/sscanf to parse each number.

Resources