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.
Related
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.
There is this linear system given by the following 2d array:
1.0 0.0 -1.0 -4.9 -5.9 -6.9 -7.9
0.0 1.0 2.0 4.4 5.4 6.4 7.4
0.0 0.0 0.0 5.7 5.7 -3.3 -3.3
0.0 0.0 0.0 2.9 2.9 2.9 2.9
0.0 0.0 0.0 7.0 -1.0 -3.0 -3.0
0.0 0.0 -20.0 -65.9 -89.9 -100.9 128.9
Whenever I get a 0 in my main diagonal (when row equals column), I want to change the order of the rows, so there's no zeroes on my main diagonal.
In this case, the row 2(counting from 0) should be traded with row 5 (also counting from 0) because with this, there is no 0s on the main diagonal.
I'm already doing that, but I'm "deleting" the first line and appending it on the end of the linear system. How should I make this logic to know where to exactly trade the rows?
The code is as follows:
void change_order(double linear[6][7], unsigned int qty) {
double aux[100];
// dynamically create an array of pointers of size `m`
double **matrix = (double **)malloc((qty + 1) * sizeof(double *));
// dynamically allocate memory of size `n` for each row
for (int r = 0; r < qty+ 1; r++) {
matrix[r] = (double *)malloc((qty + 1) * sizeof(double));
}
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
if (i == 0)
aux[j] = linear[i][j];
}
}
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
matrix[i][j] = linear[i][j];
}
}
remove_line(matrix, 0, qty);
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
linear[i][j] = matrix[i][j];
}
}
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
if (i == qty- 1) {
linear[i][j] = aux[j];
}
}
}
}
void remove_line(double ** linear, int row, unsigned int qty) {
qty--;
free(linear[row]);
while (row < qty) {
linear[row] = linear[row + 1];
row++;
}
}
int main() {
double matrix[][7] = {
{1.0, 0.0, -1.0, -4.9, -5.9, -6.9, -7.9},
{0.0, 1.0, 2.0, 4.4, 5.4, 6.4, 7.4},
{0.0 , 0.0, 0.0, 5.7, 5.7, -3.3, -3.3},
{0.0 , 0.0, 0.0, 2.9, 2.9, 2.9, 2.9},
{0.0 , 0.0, 0.0, 7.0, -1.0, -3.0, -3.0},
{0.0 , 0.0, -20.0, -65.9, -89.9, -100.9, 128.9}
};
change_order(matrix, 6);
}
Example input:
0 3 2 28
4 0 2 24
2 3 0 16
4 2 1 0
Can be exchanged for:
4 0 2 24
2 3 0 16
4 2 1 0
0 3 2 28
If I'm understanding your requirements correctly, would you please try the following:
#include <stdio.h>
#include <stdlib.h>
#define ROWS 6
#define COLS 7
/*
* search for a trade line to be swapped below the n'th row
*/
int search_trade(double matrix[][COLS], int qty, int n)
{
for (int i = n + 1; i < qty; i++) {
if (matrix[i][n] != 0.0) {
return i; // i'th row is a nice trade
}
}
return -1; // not found
}
/*
* swap m'th row and n'th row
*/
void swap(double matrix[][COLS], int qty, int m, int n)
{
int j;
double tmp;
for (j = 0; j < qty + 1; j++) {
tmp = matrix[m][j];
matrix[m][j] = matrix[n][j];
matrix[n][j] = tmp;
}
}
void change_order(double linear[][COLS], int qty) {
for (int i = 0; i < qty; i++) {
if (linear[i][i] == 0.0) { // found 0 in the diagonal
int k = search_trade(linear, qty, i); // search for the trade row
if (k < 0) { // no applicable trade
fprintf(stderr, "cannot find the row to swap. abort.\n");
exit(1);
} else {
swap(linear, qty, i, k); // swap i'th row and k'th row
}
}
}
}
/*
* print the elements of the matrix
*/
void matprint(double matrix[][COLS], int qty)
{
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty + 1; j++) {
printf("%.2f%s", matrix[i][j], j == qty ? "\n" : " ");
}
}
printf("\n");
}
int main() {
double matrix[][COLS] = {
{1.0, 0.0, -1.0, -4.9, -5.9, -6.9, -7.9},
{0.0, 1.0, 2.0, 4.4, 5.4, 6.4, 7.4},
{0.0 , 0.0, 0.0, 5.7, 5.7, -3.3, -3.3},
{0.0 , 0.0, 0.0, 2.9, 2.9, 2.9, 2.9},
{0.0 , 0.0, 0.0, 7.0, -1.0, -3.0, -3.0},
{0.0 , 0.0, -20.0, -65.9, -89.9, -100.9, 128.9}
};
matprint(matrix, ROWS);
change_order(matrix, ROWS);
matprint(matrix, ROWS);
}
Output:
0.00 1.00 2.00 4.40 5.40 6.40 7.40
0.00 0.00 0.00 5.70 5.70 -3.30 -3.30
0.00 0.00 0.00 2.90 2.90 2.90 2.90
0.00 0.00 0.00 7.00 -1.00 -3.00 -3.00
0.00 0.00 -20.00 -65.90 -89.90 -100.90 128.90
1.00 0.00 -1.00 -4.90 -5.90 -6.90 -7.90
0.00 1.00 2.00 4.40 5.40 6.40 7.40
0.00 0.00 -20.00 -65.90 -89.90 -100.90 128.90
0.00 0.00 0.00 2.90 2.90 2.90 2.90
0.00 0.00 0.00 7.00 -1.00 -3.00 -3.00
0.00 0.00 0.00 5.70 5.70 -3.30 -3.30
You'll see the 2nd row and the 5th row are swapped.
The main concept is:
Seek the diagonal elements for value 0.
If 0 is found, search for a trade row which has a non-zero value in the same column.
If no trade rows are found, the program prints an error message and aborts.
If a trade row is found, swap the rows.
[Edit]
Answering your comment, the code assumes the count of cols == count of rows + 1.
As your provided example has 4x4 matrix, let me add an extra column as:
double matrix[][COLS] = {
{0, 3, 2, 28, -1},
{4, 0, 2, 24, -1},
{2, 3, 0, 16, -1},
{4, 2, 1, 0, -1}
};
(Please note the value -1 is a dummy value and meaningless so far.)
And modify the #define lines as:
#define ROWS 4
#define COLS 5
Then the program will output:
0.00 3.00 2.00 28.00 -1.00
4.00 0.00 2.00 24.00 -1.00
2.00 3.00 0.00 16.00 -1.00
4.00 2.00 1.00 0.00 -1.00
4.00 0.00 2.00 24.00 -1.00
0.00 3.00 2.00 28.00 -1.00
4.00 2.00 1.00 0.00 -1.00
2.00 3.00 0.00 16.00 -1.00
which shows the rows are properly rearranged having no 0 values in the diagonal.
(BTW your expected result breaks having 0 in the diagonal in the last row.)
**You can make a main function like as follows:
//after passing the linear function
int i,j, temp; // declare i and j as global variables**
for(i=0,i<qty+1,i++)
{
for (j=0;j<qty+1;j++)
{
if(i==j & matrix[i][j]==0)
{
remove_line;
temp = i;
break;
}
}
} // here we are looking for a zero in the diagonal.
for (;i<qty+1;i++)
{
if(matrix[i][j]!=0)
{
matrix[temp][j] = linear[i][j]
}
}
// **here we are increasing the rows till we get a non zero element and then
interchanging the values.**
Im working with a sparse matrix and im given a text file like this:
0 3 1.2
2 5 3.2
3 0 2.1
3 5 4.2
4 5 2.2
0 0 5.2
Basically the way it works is the number 1.2 goes on the position [0] [3] and the elements of the matriz that are not mentioned stay at 0, so in this case it should look like this:
5.2 0 0 1.2 0 0
0 0 0 0 0 0
0 0 0 0 0 3.2
2.1 0 0 0 0 4.2
0 0 0 0 0 2.2
OP wrote this in the comments:
Im so sorry but my teacher clarified everything just now... it turns out that, for each line, the first number is the row, the second the column and the third the element.with the example i have above, 1.2 has to go in the position [0][3]. The matrix does not have to be square.
This makes every thing different. If you don't know the dimensions of the
matrix, then you have to read everything first, then calculate the matrix
dimensions, allocate space for the matrix and then fill it with the values.
I'd do this:
#include <stdio.h>
#include <stdlib.h>
#define BLOCK 1024
struct matrix_info {
int col;
int row;
double val;
};
void free_matrix(double **matrix, size_t rows)
{
if(matrix == NULL)
return;
for(size_t i = 0; i < rows; ++i)
free(matrix[i]);
free(matrix);
}
double **readmatrix(const char *fname, size_t *rows, size_t *cols)
{
if(fname == NULL || rows == NULL || cols == NULL)
return NULL;
double **matrix = NULL;
struct matrix_info *info = NULL;
size_t mi_idx = 0; // matrix info index
size_t mi_size = 0;
FILE *fp = fopen(fname, "r");
if(fp == NULL)
{
fprintf(stderr, "Cannot open %s\n", fname);
return NULL;
}
*rows = 0;
*cols = 0;
for(;;)
{
if(mi_idx >= mi_size)
{
struct matrix_info *tmp = realloc(info, (mi_size + BLOCK) * sizeof *info);
if(tmp == NULL)
{
fprintf(stderr, "not enough memory\n");
free(info);
fclose(fp);
return NULL;
}
info = tmp;
mi_size += BLOCK;
}
int ret = fscanf(fp, "%d %d %lf", &info[mi_idx].row, &info[mi_idx].col,
&info[mi_idx].val);
if(ret == EOF)
break; // end of file reached
if(ret != 3)
{
fprintf(stderr, "Error parsing matrix\n");
free(info);
fclose(fp);
return NULL;
}
if(*rows < info[mi_idx].row)
*rows = info[mi_idx].row;
if(*cols < info[mi_idx].col)
*cols = info[mi_idx].col;
mi_idx++;
}
fclose(fp);
// mi_idx is now the length of info
// *cols and *rows have the largest index
// for the matrix, hence the dimension is (rows + 1) x (cols + 1)
(*cols)++;
(*rows)++;
// allocating memory
matrix = calloc(*rows, sizeof *matrix);
if(matrix == NULL)
{
fprintf(stderr, "Not enough memory\n");
free(info);
return NULL;
}
for(size_t i = 0; i < *rows; ++i)
{
matrix[i] = calloc(*cols, sizeof **matrix);
if(matrix[i] == NULL)
{
fprintf(stderr, "Not enough memory\n");
free(info);
free_matrix(matrix, *rows);
return NULL;
}
}
// populating matrix
for(size_t i = 0; i < mi_idx; ++i)
{
int r,c;
r = info[i].row;
c = info[i].col;
matrix[r][c] = info[i].val;
}
free(info);
return matrix;
}
int main(void)
{
const char *fn = "/tmp/matrix.txt";
size_t rows, cols;
double **matrix = readmatrix(fn, &rows, &cols);
if(matrix == NULL)
return 1;
for(size_t i = 0; i < rows; ++i)
{
for(size_t j = 0; j < cols; ++j)
printf("%0.3f ", matrix[i][j]);
puts("");
}
free_matrix(matrix, rows);
return 0;
}
The output is (for a file with your sample data)
5.200 0.000 0.000 1.200 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 3.200
2.100 0.000 0.000 0.000 0.000 4.200
0.000 0.000 0.000 0.000 0.000 2.200
So a quick explanation of what I'm doing:
I read the file and store in an dynamically allocated array the information
about the column, the row and the value. This information is stored in the
struct matrix_info *info.
The idea is that I read every line and extract the three values. While I read
the file, I also store the largest index for the column and the row
...
if(*rows < info[mi_idx].row)
*rows = info[mi_idx].row;
if(*cols < info[mi_idx].col)
*cols = info[mi_idx].col;
...
so when the file is read, I know the dimensions of the matrix. Now all values
with their row & column are stored in the info array, so the next step is to
allocate memory for the matrix and fill the values based based on the info[i]
entries.
for(size_t i = 0; i < mi_idx; ++i)
{
int r,c;
r = info[i].row;
c = info[i].col;
matrix[r][c] = info[i].val;
}
At the end I free the memory for info and return the matrix.
Another interesting part is this:
if(mi_idx >= mi_size)
{
struct matrix_info *tmp = realloc(info, (mi_size + BLOCK) * sizeof *info);
if(tmp == NULL)
{
fprintf(stderr, "not enough memory\n");
free(info);
fclose(fp);
return NULL;
}
info = tmp;
mi_size += BLOCK;
}
Because you mentioned that the only thing you know about the matrix is that it
might contain up to 10000 elements, then the input file might be very big.
Instead of reallocating memory for the info elements on every loop, I allocate
chunks of 1024 (BLOCK) info elements at a time. Thus once a block is full,
the next block is allocated and so on. So I call realloc only every 1024
iterations.
you need use in first :
float* sparseMatrix = malloc(sizeof(float) * 10000);
You start read the file and after the first line read you know the nomber of colums and the number of row is the number of line read. After you can reduce the matrix if you want.
free(sparseMatrix );
sparseMatrix = malloc(sizeof(float) * nbRow*nbColum);
You simply don't have enough information to construct an appropriate matrix. In your cited case, you know you have AT LEAST 5 rows and AT LEAST 6 columns, but you don't know exactly how many rows m and columns n are in your matrix. So for your given input:
0 3 1.2
2 5 3.2
3 0 2.1
3 5 4.2
4 5 2.2
0 0 5.2
You could have a 5x6 matrix as:
5.2 0.0 0.0 1.2 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 3.2
2.1 0.0 0.0 0.0 0.0 4.2
0.0 0.0 0.0 0.0 0.0 2.2
Or you could have a 10x6 matrix as:
5.2 0.0 0.0 1.2 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 3.2
2.1 0.0 0.0 0.0 0.0 4.2
0.0 0.0 0.0 0.0 0.0 2.2
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
This ambiguity is a problem as the first matrix is vastly different that the second.
Also, the point of a sparse matrix is to be efficient with memory and/or processing time. If you allocate a full array of m rows and n columns then you have a dense matrix representation instead.
There's no real way of knowing what's in a file unless you completely read the file yourself first.
Since you know that there will be max 10k elements, you can statically allocate an array of that size first, and then load the numbers into the until you parse an EOF.
float sparseMatrix[10000];
It just means that your program will always allocate the space for 10k elements regardless of how many elements are actually in the array. If you assume that each element takes up 4 bytes, then you'll only be using ~40kB of memory. This is probably the easiest solution.
The other option would be to read the file fully, figure out the required size, and dynamically allocate that size, then read through the whole file again whilst populating the elements.
// Assume numberOfElements was determined by reading through the file first
float* sparseMatrix = malloc(sizeof(float) * numberOfElements);
Though this method will use less memory, it requires two full reads of the file + the overhead of calling malloc.
You can measure the number of rows and columns and then define your 2d array. Of course, this will increase the time complexity! If you don't care about the size of the memory, you can define your array with the max columns and rows! So you should choose between big time complexity and big memory size.
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
This is my print statement:
printf("%d %f\n",kPower, raisePower);
This is my output:
-4 0.000100
-3 0.001000
-2 0.010000
-1 0.100000
0 1.000000
1 10.000000
2 100.000000
3 1000.000000
4 10000.000000
I want it to be printed like this:
UPDATE
So I made my positive values line up:
-4 0.0
-3 0.0
-2 0.0
-1 0.1
0 1.0
1 10.0
2 100.0
3 1000.0
4 10000.0
This is my new code so far:
printf("%d %10.1f\n",kPower, raisePower);
I don't know, should I make a for loop to print each one (positive results vs negative result) in a different format?
#include <stdio.h>
char *get_number_formatted(double f)
{
static char buf[128]; // this function is not thread-safe
int i, j;
i = snprintf(buf, 128, "%20.10f", f) - 2;
for (j = i - 8; i > j; --i)
if (buf[i] != '0')
break;
buf[i + 1] = '\0';
return buf;
}
int main(void)
{
int i;
for (i = -4; i < 5; ++i)
printf("%5d %s\n", i, get_number_formatted(pow(10.0, i)));
return 0;
}
http://ideone.com/KBiSu0
Output:
-4 0.0001
-3 0.001
-2 0.01
-1 0.1
0 1.0
1 10.0
2 100.0
3 1000.0
4 10000.0
printf() cannot print a variating length of decimal digits, so basically what I did was print the formatted number into a buffer and then cut the exceeding zeros.
Try calculating the powers first using pow() from math.h and then:
You can use %10f to precede the number with blanks in the example total of 10 spaces:
printf ("Preceding with blanks: %10f \n", 10000.01);
Source: cplusplus.com
Basicly you can use variable length to perform this:
printf("%d %.*lf", kPower, -kPower, raisePower);
Advantage over other methods is that this method does not need any extra buffer(s)
With a little help of modf, you can use %g to skip the trailing zeroes and \b to skip the leading zero:
#include <stdio.h>
#include <math.h>
int main(void)
{
int i, iarr[] = {-4, -3, -2, -1, 0, 1, 2, 3, 4};
double darr[] = {0.0001, 0.001, 0.01, 0.1, 1., 10., 100., 1000., 10000.};
double intpart, fractpart;
for (i = 0; i < 9; i++) {
fractpart = modf(darr[i], &intpart);
if (fractpart == 0.0)
printf("%10d%10d.0\n", iarr[i], (int)intpart);
else
printf("%10d%10d\b%g\n", iarr[i], (int)intpart, fractpart);
}
return 0;
}
Output:
-4 0.0001
-3 0.001
-2 0.01
-1 0.1
0 1.0
1 10.0
2 100.0
3 1000.0
4 10000.0
Try this example code
float y[7]={0.000100f,0.0010f,0.0100,0.1000f,1.0f,10.000f,100.00f};
int a[7]={-4,-3,-2,-1,0,1,2};
for(int i=0;i<7;i++)
printf("%2d%20f\n",a[i],y[i]);
Output will like that.
You can use sprintf and then trim the zeros. This is the same idea as #Havenard's answer, but writing spaces over the zeros instead of cutting the string.
And my C-style is somewhat different FWIW. My style is that I don't want to count or do any arithmetic in my head; that's what the C optimizer is for :).
#include <math.h>
#include <stdio.h>
#include <string.h>
int main() {
int kPower;
for(kPower=-4; kPower<5; kPower++){
enum { bufsize = 2+5+10+1+4+1+1 };
char buf[bufsize];
int j,n,i;
double raisePower = pow(10,kPower);
//printf("%2d %10.4f\n",kPower,raisePower);
snprintf(buf,bufsize,"%2d %10.4f\n",kPower,raisePower);
j=strchr(buf,'.')-buf;
j+=1;
n=strchr(buf+j,'\n')-buf;
for (i=n-1; i>j; i--)
if (buf[i]=='0')
buf[i]=' ';
else
break;
printf("%s",buf);
}
return 0;
}
Output:
-4 0.0001
-3 0.001
-2 0.01
-1 0.1
0 1.0
1 10.0
2 100.0
3 1000.0
4 10000.0
use printf like this:
printf( "%5d %10.1f\n",kPower, raisePower);
this will result in kPower being printed,
right justified,
in 5 columns
- sign in the right place
this will result in raisePower being printed with:
10 columns
leading 0s replaced by spaces
except 1 digit (could be 0) to the left of the decimal point
1 (rounded) digit to the right of the decimal point
- signs being printed at the proper location
decimal point being aligned