Closed. This question is
off-topic。它当前不接受答案。
想改善这个问题吗?
Update the question,所以它是
on-topic,用于堆栈溢出。
2年前关闭。
我正在尝试构建一个程序,该程序可以读取涉及以下信息的数据:
产品代码,BoM站,年,月,日,最大值(C),最小值(C)
IDCJAC0010,86282,1971,1,1,19.7,11.5
IDCJAC0010,86282,1971,1,2,19.5,9.8
IDCJAC0010,86282,1971,1,3,18.9,11.1
IDCJAC0010,86282,1971,1,4,21.1,12.8
IDCJAC0010,86282,1971,1,5,24.8,14.3
IDCJAC0010,86282,1971,1,6,28.3,14.6
IDCJAC0010,86282,1971,1,7,35.5,14.6
我试图建立一个循环以读取数据并打印特定行...但是以某种方式,它不会从一行读取到另一行?
#define MAX_RECORD 20000
_read_int_arrays(int location[], int yy[], int mm[], int dd[], double max[], double min[], int maxvals)
{
int Line = 1;
int next_location, next_yy, next_mm, next_dd;
double next_min, next_max;
scanf("IDCJAC0010,%d,%d,%d,%d,%lf,%lf\n", &next_location, &next_yy, &next_mm, &next_dd, &next_max, &next_min);
while ( Line < MAX_RECORD ) {
yy[Line] = next_yy;
mm[Line] = next_mm;
dd[Line] = next_dd;
min[Line] = next_min;
max[Line] = next_max;
++Line;
scanf("IDCJAC0010,%d,%d,%d,%d,%lf,%lf\n", &next_location, &next_yy, &next_mm, &next_dd, &next_max, &next_min);
}
printf(" date:%d/%d/%d\n", yy[1], mm[1], dd[1]);
return 0;
}
输出的日期是date:6422476/6102276/6102276
没有n尝试过,仍然有同样的问题。
否。请勿使用并行数组。使用一种结构表示每个数据记录。例如,
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
struct record {
char product[12];
int station;
int date;
double max;
double min;
};
#define DATE_PACK(year, month, day) ((year)*10000 + (month)*100 + (day))
#define DATE_YEAR(date) ((date) / 10000)
#define DATE_MONTH(date) (((date) / 100) % 100)
#define DATE_DAY(date) ((date) % 100)
如果然后定义一个比较两个记录的函数,如果它们按参数的顺序返回
-1
,如果相等则返回
0
,如果第一个在第二个之后则返回
+1
,则可以对它们进行排序使用
qsort()
C库函数记录。例如,要基于日期排序,同一数据上的记录按工作站排序,而同一工作站上同一工作站上的记录则按min字段排序:
int compare_records(const void *ptr1, const void *ptr2)
{
const struct record *rec1 = ptr1;
const struct record *rec2 = ptr2;
if (rec1->date < rec2->date)
return -1;
else
if (rec1->date > rec2->date)
return +1;
if (rec1->station < rec2->station)
return -1;
else
if (rec1->station > rec2->station)
return +1;
if (rec1->min < rec2->min)
return -1;
else
if (rec1->min > rec2->min)
return +1;
return 0;
}
void sort_records(struct record *array, size_t count)
{
if (count > 1)
qsort(array, count, sizeof array[0], compare_records);
}
您可以动态分配一个记录,而不是固定长度的静态记录数组,并在必要时重新分配它。我经常建议使用类似于POSIX.1
getline()
函数的接口,该接口可以轻松读取无限长度的行以及带有嵌入式nul字节的行,而不会出现问题。
例如,考虑
size_t read_records(struct record **arrayptr, size_t *sizeptr, FILE *in)
{
struct record *array;
size_t count = 0;
size_t max_count;
if (!arrayptr || !sizeptr || !in) {
errno = EINVAL;
return 0;
}
if (ferror(in)) {
errno = EIO;
return 0;
}
/* If *sizeptr is 0, we have no array yet. */
if (!*arrayptr || !*sizeptr) {
*arrayptr = NULL;
*sizeptr = 0;
}
array = *arrayptr;
max_count = *sizeptr;
while (1) {
char buffer[256], *line;
char product[12];
int station, year, month, day;
double min, max;
line = fgets(buffer, sizeof buffer, in);
if (!line) {
if (ferror(in) || !feof(in)) {
/* Read error. */
errno = EIO;
return count;
}
/* End of input. No error. */
errno = 0;
return count;
}
/* Ensure "product" is padded with nuls, not garbage. */
memset(product, '\0', sizeof product);
/* Parse this line. */
if (sscanf(line, "%11[^,],%d,%d,%d,%d,%lf,%lf", product,
&station, &year, &month, &day, &max, &min) != 7) {
/* Bad input format. Choose a better errno constant! */
errno = ENOMSG;
return count;
}
if (month < 1 || month > 12 || day < 1 || day > 31) {
/* Bad input format. Choose a better errno constant! */
errno = ENOMSG;
return count;
}
/* Reallocate more records if needed. */
if (count >= max_count) {
/* See notes on "allocation policy"! */
const size_t max_temp = (count | 1023) + 1021;
struct record *temp;
temp = realloc(array, max_temp * sizeof array[0]);
if (!temp) {
/* Out of memory. */
errno = ENOMEM;
return count;
}
*arrayptr = temp;
array = temp;
*sizeptr = max_temp;
max_count = max_temp;
}
/* Add record to array. */
memcpy(array[count].product, product, sizeof product);
array[count].station = station;
array[count].date = DATE_PACK(year, month, day);
array[count].max = max;
array[count].min = min;
count++;
}
}
您可以使用上述
read_records()
例如
struct record *array = NULL;
size_t array_num;
size_t array_max = 0;
array_num = read_records(&array, &array_max, stdin);
if (errno) {
/* Failure! */
}
/* This sorts them according to date, station, and min. */
sort_records(array, array_num);
上面的
array
是指向记录的指针-您可以使用例如
array[3].product
引用第四条记录(0是第一条)的产品字符串,或者
DATE_YEAR(array[2].date)
获得第三条记录的年份。
array_num
是数组中的记录数:
array[0]
是第一个记录,而
array[array_num-1]
是最后一个记录。
array_max
是
array
中实际分配的记录数,因此从技术上讲,您最多可以引用
array[array_max-1]
,但在
array_num-1
以上,它们将没有任何有意义的数据,只是垃圾。
上面的分配策略(即,当没有足够的空间容纳现有条目时要分配的额外空间量)是将当前条目的数量四舍五入到1024的下一个倍数,然后加1020:
const size_t max_temp = (count | 1023) + 1021;
它没有什么魔术,这只是实现它的一种非常简单的方法。在最坏的情况下,它会分配大约2043个记录“太多”。如果文件有成千上万的记录,那么它会“经常”调用
realloc()
;意思是,这比在已经有很多记录的情况下分配策略使用较大的块时要慢一些。有些人建议总是将大小增加一倍,但我建议将其上限限制在几兆字节左右,以限制可能未使用但已分配的内存量。
例如,要分配至少一千条记录,然后将其加倍达到一百万条记录,然后一次添加一百万条记录,
size_t max_temp;
if (count < 1000)
max_temp = 1000;
else
if (count < 1000000)
max_temp = 2 * count;
else
max_temp = count + 1000000;
只要代码计算出的
max_temp
大于
count
,它将起作用。是的,即使您使用了
max_temp = count + 1
,它也会为每次读取的新记录调用
realloc()
(因此会大大降低读取部分的速度)。我这样做的原因是,您可以识别
realloc()
调用周围的“分配策略”代码,并对它对实际代码的影响有所了解。
您还应该认识到
arrayptr
和
sizeptr
分别是指向数组指针的指针和分配给该数组的记录数。该函数的返回值是读取的记录数。如果
errno
在调用后为零,则没有错误;否则,
errno
的值描述该错误。
如果
realloc()
失败,则旧的动态数组不会被破坏。这就是为什么仅在重新分配成功时才更新
*arrayptr
处的数组指针和
*sizeptr
处分配的记录数的原因。
除了
errno
常量(
EINVAL
,
EIO
,
ENOMSG
和
ENOMEM
,它们在POSIX.1中定义并且并非在所有C库中都可用)之外,该代码有效并且实际上是一种实用的模式。也就是说,如果您放弃了对当前作业的简单答案的想法,而实际上花了一些时间来理解上述代码的工作原理,以及如何将其应用于其他类似问题,那么您将在自己的工具中获得强大的工具皮带使用。这就是为什么我写了这个答案。我还写了它,超出了您的原始参数,因此如果不了解它,它就不是复制和传递作为您自己的家庭作业的可行之选;一个关于它的问题足以应付任何作弊尝试。
我是一名优秀的程序员,十分优秀!