如何改进我的代码以从文本表中填充数组?

时间:2017-12-16 11:14:42

标签: c arrays data-structures io

我是精神健康诊所的研究助理,我正在尝试编写一个C程序,将原始分数(在四个分测试中)转换为T分数。 C,无论好坏,都是我最熟悉的语言,但是我已经写了一段时间了,所以请原谅我的无知。

每个子测试的每个原始分数仅对应一个T分数。但是,反过来并不成立:每个T分数可以对应多个原始分数(特别是在比例的任何一个极端),而某些T分数不对应任何原始分数。

我在文本文件中表示此数据的问题的解决方案是表示代表T的八列中的数据,每个奇数列(索引[0],[2],[4]和[6])得分和每个偶数列代表与之对应的原始分数,这似乎现在解决了这个问题。如果T分数没有相应的原始分数,我已插入-1以保持fscanf满意。

然而,我希望你能帮助我找出更智能的解决方案。我还想知道是否有更好的数据结构可以让我智能地表示和操纵T分数与原始分数之间的不对称关系,也许这样每个T分数和范围都会有一个条目可能产生该T分数的子测试的可能值?该文件如下所示:

20,0,20,0,20,-1,20,0
20,1,20,1,21,-1,20,1
20,2,20,2,22,0,20,2
20,3,20,3,23,1,20,3
20,4,20,4,24,2,20,4
20,5,20,5,25,3,20,5
20,6,20,6,26,4,20,6
20,7,20,7,27,5,20,7
20,8,20,8,28,6,20,8
20,9,20,9,29,7,20,9

你可以看到我到目前为止的内容。它执行以下操作:

  1. 使用for循环和二维整数数组,它从文件中检索数据并将其输入数组。

    该表有83行,所以我将循环限制为83次迭代,但我确定必须有更好的方法来执行此操作,因此我不必将其硬编码到程序中(我想也许是一个while循环,当检测到某个数字,比如-2时停止?)。

    -1技巧似乎现在有效,但我也希望有更好的方法来处理表输入,以便我可以按原样使用它。但我并不能真正理解fscanf的语法,以便更好地实现更好的东西。你能给我任何指示吗?

  2. 使用进一步的for循环,它会遍历原始分数行,并检查用户输入的分数与其在表格中的位置之间的身份。我想知道是否有一种聪明的方法可以将这些操作嵌套到上级for循环中?

  3. 当数字匹配时,会分配T分数并打印结果。

  4. 以下是代码:

    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      int tab[8][83];
      int r_v, r_s, r_bd, r_mr;
      int t_v, t_s, t_bd, t_mr;
      int i;
      FILE *input;
    
      input = fopen(argv[1], "r");
    
      printf("Subtest A score?\n");
      scanf("%i", &r_v);
    
      printf("Subtest B score?\n");
      scanf("%i", &r_s);
    
      printf("Subtest C score?\n");
      scanf("%i", &r_bd);
    
      printf("Subtest D score?\n");
      scanf("%i", &r_mr);
    
      for (i = 0; i < 83; i++) {
        fscanf(input, "%i,%i,%i,%i,%i,%i,%i,%i", &tab[0][i], &tab[1][i], &tab[2][i], &tab[3][i], &tab[4][i], &tab[5][i], &tab[6][i], &tab[7][i]);
        }
    
      for (i = 0; i < 83; i++) {
        if (r_v == tab[1][i]) {
          t_v = tab[0][i];
        }
      }
    
      for (i = 0; i < 83; i++) {
        if (r_s == tab[3][i]) {
          t_s = tab[2][i];
        }
      }
    
      for (i = 0; i < 83; i++) {
        if (r_bd == tab[5][i]) {
          t_bd = tab[4][i];
        }
      }
    
      for (i = 0; i < 83; i++) {
        if (r_mr == tab[7][i]) {
          t_mr = tab[6][i];
        }
      }
    
      printf("The participant had the following raw scores: %d, %d, %d, and %d.\n", r_v, r_s, r_bd, r_mr);
      printf("Which corresponds to the following T scores: %d, %d, %d, and %d.\n", t_v, t_s, t_bd, t_mr);
    
      return 0;
    }
    

3 个答案:

答案 0 :(得分:2)

错误处理

首先,发布的代码缺少错误检查。用户可能无法提供文件名,或者可能提供不存在的文件名。该文件可能无法打开。用户可以输入非数字输入。表中可能找不到输入值。

通过在程序开头检查argc,可以捕获无法提供文件名的信息。无法打开文件可以通过检查从fopen()返回的值并在返回空指针时退出消息来处理。

如果在表中未找到输入值,则相关变量中不会存储任何值。处理此问题的一种方法是将关联变量初始化为表中不期望的标记值。我在下面的代码中选择了-1

要处理用户输入,可以添加get_integer()函数,该函数将输入提示消息作为参数并返回输入数字。如果用户输入格式错误的输入,该函数将继续提示输入,直到给出正确的输入。此函数还可以验证输入是否为非负整数,以防止根据用户输入值-1分配值。

一个改进可能是对用户在退出程序之前提供错误输入的次数设置上限。

数据结构

我建议不要将表存储为二维数组并通过索引访问表的各个字段,而是建议为表的行创建一个结构,以及这些table[]数组struct }秒。这将允许描述性的字段名称,并使代码更加清晰。

阅读文件

我建议使用fgets()从文件中获取行。当达到文件结尾时,此函数返回空指针,允许使用while循环进行控制。 sscanf()函数可用于解析每一行并将值存储在适当的位置。与返回有意义值的所有函数一样,应检查从sscanf()返回的值,以确保输入符合预期。如果不是,则可以通过退出程序并显示错误消息来处理该情况。我还会考虑在之前从文件构建表格,要求更多的用户输入。

当每一行成功添加到表中时,可以递增line计数器以跟踪table[]数组中的行数。

搜索表

这里只需要一个循环。 line计数器可用于建立要检查的行数的上限。由于OP建议每个搜索值都是唯一的,一旦找到并存储了相关变量,关联变量就不会再次更改。如果在表中未找到搜索值,则关联变量将继续保持初始值(-1)。

一个改进是添加一个标志来指示何时找到所有搜索值,并在发生这种情况时提前退出循环。

以下是一个示例程序:

#include <stdio.h>
#include <stdlib.h>

#define MAX_ROWS  100
#define BUF_SZ    1024

struct Record
{
    int t_v;
    int r_v;
    int t_s;
    int r_s;
    int t_bd;
    int r_bd;
    int t_mr;
    int r_mr;
};

int get_integer(const char *prompt);

int main(int argc, char *argv[])
{
    struct Record table[MAX_ROWS];
    int r_v, r_s, r_bd, r_mr;
    int t_v = -1;
    int t_s = -1;
    int t_bd = -1;
    int t_mr = -1;
    FILE *input;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s filename\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    input = fopen(argv[1], "r");

    if (input == NULL) {
        fprintf(stderr, "Unable to open file: %s\n", argv[1]);
        exit(EXIT_FAILURE);
    }

    /* Read table  into array */
    int line = 0;
    char buffer[BUF_SZ];
    while (fgets(buffer, sizeof buffer, input) != NULL) {
        if (sscanf(buffer, "%i,%i,%i,%i,%i,%i,%i,%i",
                   &table[line].t_v,
                   &table[line].r_v,
                   &table[line].t_s,
                   &table[line].r_s,
                   &table[line].t_bd,
                   &table[line].r_bd,
                   &table[line].t_mr,
                   &table[line].r_mr)
            != 8) {
            fprintf(stderr, "Format error in line %d\n", line);
            exit(EXIT_FAILURE);
        }
        ++line;
    }
    fclose(input);

    r_v = get_integer("Subtest A score?\n");
    r_s = get_integer("Subtest B score?\n");
    r_bd = get_integer("Subtest C score?\n");
    r_mr = get_integer("Subtest D score?\n");

    for (int i = 0; i < line; i++) {
        if (r_v == table[i].r_v) {
            t_v = table[i].t_v;
        }
        if (r_s == table[i].r_s) {
            t_s = table[i].t_s;
        }
        if (r_bd == table[i].r_bd) {
            t_bd = table[i].t_bd;
        }
        if (r_mr == table[i].r_mr) {
            t_mr = table[i].t_mr;
        }
    }

    printf("The participant had the following raw scores: "
           "%d, %d, %d, and %d.\n",
           r_v, r_s, r_bd, r_mr);
    printf("Which corresponds to the following T scores: "
           "%d, %d, %d, and %d.\n",
           t_v, t_s, t_bd, t_mr);

    return 0;
}

int get_integer(const char *prompt)
{
    char buf[BUF_SZ];
    int ret;

    do {
        printf("%s", prompt);
        fflush(stdout);
        if (fgets(buf, sizeof buf, stdin) == NULL) {
            fprintf(stderr, "Input error in get_integer()\n");
            exit(EXIT_FAILURE);
        }
    } while (sscanf(buf, "%i", &ret) != 1 || ret < 0);

    return ret;
}

以下是使用发布的输入文件的示例交互:

λ> ./tvals t_vals.dat
Subtest A score?
3
Subtest B score?
4
Subtest C score?
5
Subtest D score?
6
The participant had the following raw scores: 3, 4, 5, and 6.
Which corresponds to the following T scores: 20, 20, 27, and 20.

答案 1 :(得分:0)

嗯...我没有很好地得到那些代码。 我可以看到,如果A得分为5,则pip3 install twisted 为20(如果得分为0则为0)。 我没有看到您将文件中的值加载到t_v矩阵。 所以tab也是单元化的。 如果你想改进代码,可以使用Anothed。 你做了5个循环..当你可以简单地将所有这些合并为一个。 一个tab循环,顶部有for,然后是你的所有条件。

答案 2 :(得分:0)

#include <stdio.h>
#include <stdlib.h>

#define NO_OF_ROW       100     //You can change if no of rows increases
#define EACH_LINE_SIZE  100

#define SUBTEST_A       1
#define SUBTEST_B       3
#define SUBTEST_C       5
#define SUBTEST_D       7

int main(int argc, char *argv[])
{
    int tab[8][NO_OF_ROW] = {{0}};
    int r_v, r_s, r_bd, r_mr;
    int t_v=0, t_s=0, t_bd=0, t_mr=0;
    int i;
    FILE *input;
    int no_rows =0;

    char* line = malloc(EACH_LINE_SIZE);

    input = fopen("User.txt", "r");

    if(NULL == input)
    {
        return 0;
    }

    printf("Subtest A score?\n");
    scanf("%i", &r_v);

    printf("Subtest B score?\n");
    scanf("%i", &r_s);

    printf("Subtest C score?\n");
    scanf("%i", &r_bd);

    printf("Subtest D score?\n");
    scanf("%i", &r_mr);

    while (fgets(line, EACH_LINE_SIZE, input) != NULL)
    {
        sscanf(line, "%d,%d,%d,%d,%d,%d,%d,%d", &tab[0][i], &tab[1][i], &tab[2][i], &tab[3][i], &tab[4][i], &tab[5][i], &tab[6][i], &tab[7][i]);
        //printf("%d,%d,%d,%d,%d,%d,%d,%d\n", tab[0][i], tab[1][i], tab[2][i], tab[3][i], tab[4][i], tab[5][i], tab[6][i], tab[7][i]);
        i++;
        if(NO_OF_ROW <= i)
        {
            printf("Stop file reading \n");
            break;          //if the file has more line -Just end it here
        }
    }

    no_rows = i;

    for(i=0 ; i < no_rows ; i++)
    {
        if (r_v == tab[SUBTEST_A][i])
        {
            t_v = tab[SUBTEST_A-1][i];
        }

        if (r_s == tab[SUBTEST_B][i])
        {
            t_s = tab[SUBTEST_B-1][i];
        }

        if (r_bd == tab[SUBTEST_C][i])
        {
            t_bd = tab[SUBTEST_C-1][i];
        }
        if (r_mr == tab[SUBTEST_D][i])
        {
            t_mr = tab[SUBTEST_D-1][i];
        }
    }

    printf("The participant had the following raw scores: %d, %d, %d, and %d.\n", r_v, r_s, r_bd, r_mr);
    printf("Which corresponds to the following T scores: %d, %d, %d, and %d.\n", t_v, t_s, t_bd, t_mr);

    free(line);

    return 0;
}
  1. 而不是常数83,尝试使用不同的方法,因此您可以改变行数
  2. 而不是4个循环,试图适合单个循环