C语言,将2个字符串转换并组合成一个double

时间:2017-01-13 01:03:39

标签: c

我需要协助我的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*/
    ...
}

我如何编写比较函数来获取这两个字符串(整数和十进制)并将它们组合成一个双重,然后我会按升序排序? 我已经尝试过使用atofsscanf但不太确定如何在比较函数中使用二进制文件结构来完成它。

2 个答案:

答案 0 :(得分:3)

您的尝试有一些问题:

  • number结构中的record字段似乎没有用处。
  • 以二进制模式读取文件似乎很浪费,因为它可以通过这种方式轻松解析为测试字符串:

    fscanf(input, "%999s %999s", z->whole, z->decimal);
    

您甚至可以通过用.分隔整个和小数部分来使源文件完全可读,然后使用"%999s.%999s"作为格式字符串。

您可以通过以下步骤比较字符串格式的数字:

  • 跳过整个部分
  • 中的所有初始零
  • 比较得到的字符串长度:如果它们不同,如​​果第一个更短则返回-1,如果更长则返回1。
  • 如果两个字符串的长度相同,则比较它们。如果它们不同,则应返回比较结果,即返回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;
}