我需要协助我的C编程,因为我的教授太忙而无法回复(现在第六天无法在他的办公室找到,也没有回复电子邮件)。 假设我有一个定义为
的结构typedef struct {
char whole[1000];
char decimal[1000];
double number;
} record;
其中whole
代表数字(ex. 10, 20, 301, 123, 1005...)
的整个部分,而decimal
代表数字(10.123, 20.22123, 301.99181, 123.558123...)
的小数部分。数字被视为字符串并写入二进制文件,例如
10 1234 (10 is the whole part and 1234 is the decimal part of the number = 10.1234)
20 211291 (20.211291)
301 2102190 (301.2102190)
1 56615 (1.56615)
988 001 (988.001)
etc.
我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char whole[1000];
char decimal[1000];
double number;
} record;
int cmp(record *a, record *b) {
????
return ???;
}
main()
{
FILE *f = fopen("records.bin", "r+b");
if (!f)
exit(1);
fseek(f, 0, SEEK_END);
long size = ftell(f);
long N = size / sizeof(record);
fseek(f, 0, SEEK_SET);
record *z = malloc(size);
fread(z, sizeof(record), N, f);
qsort(z, N, sizeof(record), (int(*)(const void*, const void*))cmp);
/* fopen (wb) fwrite(...) flush, free, fclose*/
...
}
我如何编写比较函数来获取这两个字符串(整数和十进制)并将它们组合成一个双重,然后我会按升序排序?
我已经尝试过使用atof
和sscanf
但不太确定如何在比较函数中使用二进制文件结构来完成它。
答案 0 :(得分:3)
您的尝试有一些问题:
number
结构中的record
字段似乎没有用处。以二进制模式读取文件似乎很浪费,因为它可以通过这种方式轻松解析为测试字符串:
fscanf(input, "%999s %999s", z->whole, z->decimal);
您甚至可以通过用.
分隔整个和小数部分来使源文件完全可读,然后使用"%999s.%999s"
作为格式字符串。
您可以通过以下步骤比较字符串格式的数字:
strcmp(a->whole, b->whole)
。return strcmp(a->decimal, b->decimal);
现在编写代码是你的任务。理想情况下,您的代码应该在不更改记录的情况下实现上述步骤。
答案 1 :(得分:0)
而不是使用此struct
:
typedef struct {
char whole[1000];
char decimal[1000];
double number[1000];
} record;
使用它会好得多:
typedef struct {
char whole[1000];
char decimal[1000];
double number;
} record;
然后创建一个record
结构数组,如下所示:
size_t starting_size = 10;
record *records = malloc(starting_size * sizeof(record));
分配初始10
条记录。如果文件中有更多行,如果需要,您可以realloc()
更多空间。
realloc()
调整指向的内存块的大小,该内存块之前由malloc()
分配。
您可以使用fscanf()
简单地阅读该文件,如另一个答案所述。将这些值读入字符串后,您只需将所有内容连接成一个字符串,然后使用atof()
将字符串转换为double
。
以下是一个例子:
char *whole = 123;
char *decimal = 456;
char *point = ".";
double number;
char *whole_number = malloc(strlen(whole) + strlen(decimal) + 2);
/* check return value */
*whole_number = '\0';
strcat(whole_number, whole);
strcat(whole_number, point);
strcat(whole_number, decimal);
/* string "123.456" created */
number = atof(whole_number);
/* double number = 123.456 created */
/* free() whole_number later */
完成此操作后,您可以按升序排列qsort
结构数组。这需要更完整的cmp
功能。你的功能可能是这样的:
int cmp_func(const void *a, const void *b) {
const record *num1 = (const record *)a;
const record *num2 = (const record *)b;
if (num1->number > num2->number) {
return +1;
} else if (num1->number < num2->number) {
return -1;
}
return 0;
}
然后你可以通过这样的调用简单地对数组进行排序:
qsort(records, N, sizeof(record), cmp_func);
注意:此代码仅用于举例说明如何编写此程序。只需按照上述步骤操作即可让您修复方法。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMSIZE 1000
#define INITIALSIZE 10
typedef struct {
char whole[NUMSIZE+1];
char decimal[NUMSIZE+1];
double number;
} record_t;
typedef struct {
record_t *rec;
size_t nrec;
size_t currsize;
} records_t;
char *create_number(records_t *R, size_t numbytes);
int cmp_func(const void *a, const void *b);
void read_records(FILE *filestream, records_t *R);
void print_records(records_t *R);
records_t *create_records(void);
int main(void) {
records_t *R;
FILE *fp;
fp = fopen("doublec.txt", "r");
if (fp == NULL) {
fprintf(stderr, "%s\n", "Error reading file");
return 1;
}
R = create_records();
read_records(fp, R);
printf("\nOriginal Records:\n");
print_records(R);
qsort(R->rec, R->nrec, sizeof(record_t), cmp_func);
printf("\nSorted Records:\n");
print_records(R);
free(R->rec);
R->rec = NULL;
free(R);
R = NULL;
return 0;
}
void read_records(FILE *filestream, records_t *R) {
char *number;
size_t w_size, d_size, numbytes;
while (fscanf(filestream, "%999s %999s", R->rec[R->nrec].whole, R->rec[R->nrec].decimal) == 2) {
w_size = strlen(R->rec[R->nrec].whole);
d_size = strlen(R->rec[R->nrec].decimal);
numbytes = w_size + d_size + 2;
number = create_number(R, numbytes);
R->rec[R->nrec].number = atof(number);
if (R->currsize == R->nrec) {
R->currsize *= 2;
R->rec = realloc(R->rec, R->currsize * sizeof(record_t));
if (R->rec == NULL) {
printf("Cannot reallocate %zu members.\n", R->currsize);
exit(EXIT_FAILURE);
}
}
free(number);
number = NULL;
R->nrec++;
}
}
char *create_number(records_t *R, size_t numbytes) {
char *result;
const char *decimal = ".";
result = malloc(numbytes);
if (result == NULL) {
printf("Cannot allocate %zu bytes for number.\n", numbytes);
exit(EXIT_FAILURE);
}
*result = '\0';
strcat(result, R->rec[R->nrec].whole);
strcat(result, decimal);
strcat(result, R->rec[R->nrec].decimal);
return result;
}
void print_records(records_t *R) {
size_t i;
for (i = 0; i < R->nrec; i++) {
printf("Whole Number: %-5s Decimal: %-8s Number: %-7f\n", R->rec[i].whole,
R->rec[i].decimal,
R->rec[i].number);
}
}
int cmp_func(const void *a, const void *b) {
const record_t *num1 = (const record_t *)a;
const record_t *num2 = (const record_t *)b;
if (num1->number > num2->number) {
return +1;
} else if (num1->number < num2->number) {
return -1;
}
return 0;
}
records_t *create_records(void) {
records_t *R = malloc(sizeof(*R));
if (R == NULL) {
printf("Cannot allocate struct.\n");
exit(EXIT_FAILURE);
}
R->nrec = 0;
R->currsize = INITIALSIZE;
R->rec = malloc(R->currsize * sizeof(record_t));
if (R->rec == NULL) {
printf("Cannot allocate initial %zu members.\n", R->currsize);
exit(EXIT_FAILURE);
}
return R;
}