c - 读取文件,并从临时变量创建字符串数组

标签 c

最终目标是从文件创建字符串数组。所以我有一个文件,我需要从 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 等...

最佳答案

我制作了一个工作示例来完成我认为您打算做的事情:

#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 上的 bash 中测试了代码(在 Windows 10 上):

$ 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. 我找到了 realloc()在OP的代码中调整变量数组的大小(OP中的tempHeader,我的vars)。我没有找到 - 变量名本身的内存分配。我用过strdup()为此。

  2. 我可以发誓我一直使用 strdup()过去(使用 #include <string.h> 表示正确的原型(prototype))。然而,gcc 提示了,我发现:

    As all functions from Dynamic Memory TR, strdup is only guaranteed to be available if __STDC_ALLOC_LIB__ is defined by the implementation and if the user defines __STDC_WANT_LIB_EXT2__ to the integer constant 1 before including string.h.

    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

关于c - 读取文件,并从临时变量创建字符串数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47803935/

相关文章:

c - 交换链表中的节点

C 直方图错误数字

C - 如何将数据类型 'int' 从主机转换为网络

c - 在开罗渲染周期性图像

c - 在 C 中使用套接字

c - 为什么将 main() 参数转换为 const

我可以在不损失精度的情况下打印完全可表示的 float 吗?

c - 在带有 C 的 Linux 中使用管道

c - 以下 C 程序的行为是否未定义?

检查没有 return 语句的函数的返回值