【问题标题】:Reading a file, and creating a string array from temporary variables读取文件,并从临时变量创建字符串数组
【发布时间】:2017-12-14 00:01:08
【问题描述】:

最终目标是从文件中创建一个字符串数组。所以我有一个文件,我需要从 temp1、temp2、temp3 等获取临时变量。我不知道提前有多少。我的第一个想法是从我使用 strcat 找到的变量创建一个普通字符串,然后使用标记拆分它。我想我可以通过正常添加字符串来绕过这个。

while(feof(inputFile))
{ 
    fscanf(inputFile, " %s ", readIn);

    if(strcmp("AND", readIn) == 0 || strcmp("OR", readIn) == 0 || strcmp("NAND", readIn) == 0 || strcmp("NOR", readIn) == 0 || strcmp("XOR", readIn) == 0)
    {
        fscanf(inputFile,  "%s ", readIn);
        fscanf(inputFile,  "%s ", readIn);
        fscanf(inputFile, "%s ", tempVar);
        //printf("the char is %c", tempVar[0]);

        //check to see if  its a temp variable since temps are always lower case
        if(tempVar[0] == 't')
        {
            numVars++;
            tempHeaders = realloc(tempHeaders, sizeof(char*) * numVars);
            int temp = numVars -1;
            printf("the variable is %s and the number is %d\n", tempVar, temp);
            tempHeaders[numVars - 1] = tempVar;
        }                       

        numGates++;
    }
}

此时变量的数量是对的,问题是添加到数组 tempHeaders 时。数组的整个值将是文件的最后一个单词,即如果最后一个单词出现了。 tempHeaders i - n 将全部消失。有任何想法吗?谢谢

我已经从 while 循环中删除了 feof 并更改为 "while(fscanf(inputFile, "%s ", readIn) != EOF){"

样本输入将是

OR IN1 IN2 temp1
OR IN3 IN4 temp2
OR IN5 IN6 temp3
OR IN7 IN8 temp4
AND temp1 temp2 temp5
AND temp3 temp4 temp6
XOR temp2 temp6 OUT1

此时的样本输出

the variable is temp1 and the number is 0
the variable is temp2 and the number is 1
the variable is temp3 and the number is 2
the variable is temp4 and the number is 3
the variable is temp5 and the number is 4
the variable is temp6 and the number is 5
Printing OUT1 
Printing OUT1 
Printing OUT1 
Printing OUT1 
Printing OUT1 
Printing OUT1 
numGates = 7, numVars = 6 

打印应该是 temp1、temp2、temp3 等...

【问题讨论】:

  • 我知道 feof 经历了额外的时间,但它不应该添加到数组中的条件?另外,我将如何在我的代码中使用它,我可以这样做 (fgets(readIn, 5000, inputFile) != NULL) 会改变我在这里所做的正常 fscanf 值吗?
  • 1.检查来自fscanf 的返回值 2. 使用正确的格式说明符以确保没有缓冲区溢出
  • 3) 在你知道它的作用之前不要使用 feof()。
  • @wildplasser - 也就是我的第一条评论

标签: c


【解决方案1】:

我做了一个工作样本来做我相信你打算做的事情:

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

char* strdup(const char *str)
{
  int len = strlen(str);
  char *str2 = malloc((len + 1) * sizeof (char));
  if (str2) strcpy(str2, str);
  return str2;
}

int main()
{
  FILE *f = stdin;
  /** @todo evaluation of command line arguments could
   * check whether input file given
   * and in that case override f with fopen().
   */
  /* read input */
  if (!f) {
    fprintf(stderr, "ERROR: Cannot read input!\n");
    return 1;
  }
  int nGates = 0, nVars = 0;
  char **vars = NULL;
  char buffer[80];
  for (int iLine = 1; fgets(buffer, sizeof buffer, f); ++iLine) {
    char *op = strtok(buffer, " \t\r\n");
    if (!op
      || strcmp(op, "AND") != 0 && strcmp(op, "OR") != 0 && strcmp(op, "XOR") != 0
      && strcmp(op, "NAND") != 0 && strcmp(op, "NOR") != 0) {
      fprintf(stderr, "ERROR in line %d: OP expected!\n", iLine);
      continue;
    }
    char *var;
    while (var = strtok(NULL, " \t\r\n")) {
      if (var[0] == 't') {
        ++nVars;
        vars = realloc(vars, sizeof (char*) * nVars);
        if (!vars) {
          fprintf(stderr, "ERROR: Out of memory!\n");
          return 1;
        }
        int iVar = nVars - 1;
        vars[iVar] = strdup(var);
        if (!vars[iVar]) {
          fprintf(stderr, "ERROR: Out of memory!\n");
          return 1;
        }
        printf("Var. #%d: '%s'\n", iVar, var);
      }
    }
    ++nGates;
  }
  /* evaluate input */
  printf("Report:\n");
  printf("nGates: %d, nVars: %d\n", nGates, nVars);
  for (int i = 0; i < nVars; ++i) {
    printf("vars[%d]: '%s'\n", i, vars[i]);
  }
  /* done */
  return 0;
}

我在 cygwin(Windows 10 上)的 bash 中测试了代码:

$ gcc --version
gcc (GCC) 6.4.0

$ gcc -std=c11 -o testStrtok testStrtok.c

$ ./testStrtok <<'EOF'
OR IN1 IN2 temp1
OR IN3 IN4 temp2
OR IN5 IN6 temp3
OR IN7 IN8 temp4
AND temp1 temp2 temp5
AND temp3 temp4 temp6
XOR temp2 temp6 OUT1
EOF
Var. #0: 'temp1'
Var. #1: 'temp2'
Var. #2: 'temp3'
Var. #3: 'temp4'
Var. #4: 'temp1'
Var. #5: 'temp2'
Var. #6: 'temp5'
Var. #7: 'temp3'
Var. #8: 'temp4'
Var. #9: 'temp6'
Var. #10: 'temp2'
Var. #11: 'temp6'
Report:
nGates: 7, nVars: 12
vars[0]: 'temp1'
vars[1]: 'temp2'
vars[2]: 'temp3'
vars[3]: 'temp4'
vars[4]: 'temp1'
vars[5]: 'temp2'
vars[6]: 'temp5'
vars[7]: 'temp3'
vars[8]: 'temp4'
vars[9]: 'temp6'
vars[10]: 'temp2'
vars[11]: 'temp6'

$ 

注意事项:

  1. 我在 OP 的代码中找到了一个 realloc() 来调整变量数组的大小(OP 中的 tempHeader,我的 vars)。我没有找到的——为变量名本身分配内存。我为此使用了strdup()

  2. 我可以发誓我过去一直使用strdup()#include &lt;string.h&gt; 是正确的原型)。但是,gcc 投诉了,我发现:

    与 Dynamic Memory TR 中的所有函数一样,只有在实现定义了 __STDC_ALLOC_LIB__ 并且用户在包含 string.h 之前将 __STDC_WANT_LIB_EXT2__ 定义为整数常量 1 时,才能保证 strdup 可用。

    cppreference.com
    我只是制作了自己的版本——它并不太复杂。

  3. strtok() 就是这样一个函数……嗯。它非常古老并且有局限性,在某些情况下会很危险。 (例如,您不应该在线程中使用它。)但是,抛开这些顾虑,它可以完美地完成所需的工作(并且此代码中没有多线程)。

  4. 我使用了固定大小的输入缓冲区char buffer[80]; 来保持样本简短。在一个富有成效的项目中,我当然会做一些更复杂的事情来读取“任意”长度的行——而且我当然需要更多的代码。

  5. 在 OP 的预期输出中,没有重复的变量。但是,代码示例没有提供任何试图阻止它的代码。因此,我也没有。为此,必须插入以下代码(在唯一一次出现 ++nVars; 之前):

    int found = 0;
    for (int i = 0; i < nVars; ++i) {
      if (found = (strcmp(var, vars[i]) == 0)) break;
    }
    if (found) continue; /* continues the while (var = strtok(NULL, " \t\r\n")) loop */
  6. 提供的代码没有free() 分配的内存。事实上,这不是问题——操作系统会在离开main() 后完成这项工作。但是,“干净”的解决方案是通过以下方式显式清除 vars

    /* clean-up */
    for (int i = 0; i < nVars; ++i) free(vars[i]);
    free(vars);

建议更改为 5.,输出为:

$ gcc -std=c11 -o testStrtok testStrtok.c

$ ./testStrtok <<'EOF'
OR IN1 IN2 temp1
OR IN3 IN4 temp2
OR IN5 IN6 temp3
OR IN7 IN8 temp4
AND temp1 temp2 temp5
AND temp3 temp4 temp6
XOR temp2 temp6 OUT1
EOF
Var. #0: 'temp1'
Var. #1: 'temp2'
Var. #2: 'temp3'
Var. #3: 'temp4'
Var. #4: 'temp5'
Var. #5: 'temp6'
Report:
nGates: 7, nVars: 6
vars[0]: 'temp1'
vars[1]: 'temp2'
vars[2]: 'temp3'
vars[3]: 'temp4'
vars[4]: 'temp5'
vars[5]: 'temp6'

$

ideone上的现场演示

【讨论】:

  • @DavidButler 我刚刚对我的答案做了一些小的改进。
  • 快速问题:当您使用“for (int iLine = 1; fgets(buffer, sizeof buffer, f); ++iLine)” 时“char *op = strtok(buffer,” \t \r\n");" for 循环获取一行,op 变量通过 strtok 获取该行中的每个单词?
  • char *op = strtok(buffer, " \t\r\n"); 返回一个字符串直到第一个分隔符(" \t\r\n" 中的一个字符)。因此,找到的分隔符被'\0'替换,分隔符之后的位置被内部存储。使用NULL 而不是buffer 的调用(在while (var = strtok(NULL, " \t\r\n")) 中)返回更多令牌,直到buffer 被完全消耗。这是一个很好的答案:SO: How does strtok() split the string into tokens in C?,这里有一个文档:strtok, strtok_s
猜你喜欢
  • 2021-07-18
  • 2017-10-14
  • 1970-01-01
  • 1970-01-01
  • 2015-08-28
  • 2011-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多