我正在尝试使用scanf
/ fscanf
从stl文件中读取数据,一次一个字符。我在程序中多次调用scanf
,但在第一个实例输入所有数据。它有效地运行了一段时间,但似乎只要scanf
被称为第1022或第1023次,程序就会停止并提示输入更多内容,即使有足够的内容可供扫描。
我之前编写了一个程序,在一次输入上调用scanf
超过40,000次,所以我不知道这笔交易是什么......
scanf
时,它似乎停止在getnormal()
的{{1}}处工作;
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");
}
这是输出:
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
答案 0 :(得分:1)
您的功能getnumber
有几个问题:
缓冲区num
初始化为所有'0'
,没有空终止符。您将一些字节修补到其中,直到您看到空格或换行符并调用atof
。
没有测试可以防止缓冲区溢出,无效输入可能会导致输入文件中的某些位置。
缓冲区未终止。 atof
将停止在与浮点语法不匹配的第一个字符上,但如果所有位置都是数字,则它将继续读取num
数组的末尾。
整个代码非常繁琐,语义也不清楚。
你永远不会从scanf
测试返回值:在文件结束时,其地址作为参数传递给scanf
的unsigned char的内容将是不确定的,很可能不会受到前一个值的影响......也可能导致getnumber
中的缓冲区溢出。
您的程序无法从while (1)
循环中断。迟早,您将到达文件末尾,您的代码将调用未定义的行为或陷入无限循环。
使用getchar()
或fgets
重写您的代码,并正确检查文件的结尾。
答案 1 :(得分:0)
当您处理包含超过基本“每行包含相同信息”的文本文件时,您可以更好地利用面向行的输入函数,例如{ {1}}或fgets
为了分离'读取'您的数据和'处理(或解析)您的数据经常被人们尝试将 shoehorn 转换为getline
格式字符串,导致更多的悲伤而不是好事。
正如我的评论中所提到的,当所有输入行保证保持相同类型和数量的变量,并且每行的格式完全相同时,可以使用scanf
系列输入函数相当可靠。但是,当您的数据逐行变化时,将每一行读入缓冲区然后编写处理程序来解析和验证读取的内容将会产生更强大的代码。
在开始阅读之前,你必须决定如何在内存中保存你的价值观。无论是结构,数组,组合?虽然C足够灵活,可以让您在存储数据方面拥有广泛的自由度,但您可以预先考虑数据的哪些部分相对固定以及哪些部分将继续增长,这可以帮助您找出合理的存储方案
在您的情况下,您需要的大小相对固定的数据是实体的scanf
(或name
)(例如样本数据中的label
)。普通/顶点集的数量可以是单个数字,跟踪您可以存储的最大数量也是一个数字。
从输入文件中读取时增长的数据将是 facet normal 数组和 vertex 数组的值。在这里,你需要一些阅读文件中包含的方法(可能不知道你开始时有多少)。当然,如果您不需要存储数据,只是在读取时使用这些值,这不是一个问题,但在大多数情况下,您希望能够存储您的数据,以便将其传递给代码中可以使用的其他部分。
虽然你可以通过多种方式实现它,一个嵌套的结构,其中固定值是外部或基本结构的成员,它还包含指向数据的指针(或 normal <的嵌套结构/ em>和 vertex 数组是有意义的。使用简单的 create 或初始化函数可以让生活更轻松,每次新命名的实体都会分配和初始化结构及其值正在阅读。
在设置了如何保存/存储数据之后,只需要读取每一行,检查/解析行内容,并根据您在每行中找到的内容采取适当的操作。您还应该确保在每一行中得到您期望找到的内容,并在代码读取不理解的行时发出警告或抛出错误。
没有更好的方法将这些部分组合在一起,而不是简短的例子来阅读您发布的输入文件,这样您就可以获得它的味道。注意:在C中有很多方法可以做到这一点,所有这些都有它们的优点/缺点,这只是一个供您考虑和提出问题的问题,以帮助您理解面向行的方法如何使您尝试做的事情受益。查看示例,让我知道您有什么问题:
Untitled-56807ca1
编译(gcc)
#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;
}
使用/输出强>
gcc -Wall -Wextra -O3 -o bin/readsolid readsolid.c
内存/错误检查
在你的动态分配内存的任何代码中,你有2个责任关于任何分配的内存块:(1)总是保留一个指向内存块起始地址的指针,所以,(2)它可以在释放时释放它不再需要了。您必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,并确认已释放已分配的所有内存。
对于Linux $ ./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
是正常的选择。有许多微妙的方法来滥用可能导致实际问题的内存块,没有理由不这样做。每个平台都有类似的记忆检查器。它们都很简单易用。只需通过它运行您的程序。
valgrind
注意:此示例的结果比我原先设想的要长,但要为任何相对复杂的数据集提供足够的验证,需要一些代码才能正确完成。祝你好运。