【问题标题】:Output problems in cc中的输出问题
【发布时间】:2014-12-04 14:57:41
【问题描述】:

我对@9​​87654321@ 数组的输出有疑问。所以首先我对名为Carss.txt 的文件进行标记,只抓取第三列和第五列,并将结果分别存储在make[] 数组和year[] 数组中。

我测试了make[] 数组,看看它是否会输出我想要的结果。它在while(fgets) 循环内部进行,但是当我在while(fgets) 外部对其进行测试时,它正在重复。

我不明白有什么问题。下面提供了我的程序和文本文件。

while(fgets) 循环内 make 数组的输出:(我想要的)

FORD
FORD
JAYCO

while(fgets) 循环外的 make 数组输出:(不是我想要的)

JAYCO
JAYCO
JAYCO

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

int main() {
    FILE * fp;
    char * filename = "Carss.txt";
    char lines[100000], blank[100000];
    char * token, * del = " ";
    int i = 0, c, d = 0, j;
    char * make[10000];
    char * year[10000];
    if ((fp = fopen(filename, "r")) == NULL) /* Opens the file */ {
        printf("can't open %s\n", filename);
        exit(1);
    }
    c = 0;
    while (fgets(lines, sizeof(lines), fp) != NULL) {
        token = strtok(lines, "\t");
        i = 1;
        while (i < 5) {
            token = strtok(NULL, "\t");
            if (i == 2) {
                make[c] = token;
            }
            if (i == 4) {
                year[c] = token;
            }
            i++;
        }
        printf("%s\n", make[c]); /* OUTPUT OF THE ARRAY HERE IS WHAT I WANTED */
        c++;
    }
    c = 0;
    while (c < 3) {
        printf("%d\n", c);
        printf("%s\n", make[c]);
        c++;
    }
}

我标记的文本文件:Carss.txt

1   02V288000   FORD    FOCUS   2001    02S41   ELECTRICAL SYSTEM:BATTERY:CABLES    FORD MOTOR COMPANY  19990719    20010531    V   291854  20030210    ODI Ford Motor Company  20021106    20021106            CERTAIN PASSENGER VEHICLES EQUIPPED WITH ZETEC ENGINES, LOOSE OR BROKEN ATTACHMENTS AND MISROUTED BATTERY CABLES COULD LEAD TO CABLE INSULATION DAMAGE. THIS, IN TURN, COULD CAUSE THE BATTERY CABLES TO SHORT RESULTING IN HEAT DAMAGE TO THE CABLES.  BESIDES HEAT DAMAGE, THE "CHECK ENGINE" LIGHT MAY ILLUMINATE, THE VEHICLE MAY FAIL TO START, OR SMOKE, MELTING, OR FIRE COULD ALSO OCCUR.   DEALERS WILL INSPECT THE BATTERY CABLES FOR THE CONDITION OF THE CABLE INSULATION AND PROPER TIGHTENING OF THE TERMINAL ENDS.  AS NECESSARY, CABLES WILL BE REROUTED, RETAINING CLIPS INSTALLED, AND DAMAGED BATTERY CABLES REPLACED.   OWNER NOTIFICATION BEGAN FEBRUARY 10, 2003.   OWNERS WHO DO NOT RECEIVE THE FREE REMEDY  WITHIN A REASONABLE TIME SHOULD CONTACT FORD AT 1-866-436-7332.    ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236). 000015339000215022000000202
2   02V288000   FORD    FOCUS   2000    02S41   ELECTRICAL SYSTEM:BATTERY:CABLES    FORD MOTOR COMPANY  19990719    20010531    V   291854  20030210    ODI Ford Motor Company  20021106    20021106            CERTAIN PASSENGER VEHICLES EQUIPPED WITH ZETEC ENGINES, LOOSE OR BROKEN ATTACHMENTS AND MISROUTED BATTERY CABLES COULD LEAD TO CABLE INSULATION DAMAGE. THIS, IN TURN, COULD CAUSE THE BATTERY CABLES TO SHORT RESULTING IN HEAT DAMAGE TO THE CABLES.  BESIDES HEAT DAMAGE, THE "CHECK ENGINE" LIGHT MAY ILLUMINATE, THE VEHICLE MAY FAIL TO START, OR SMOKE, MELTING, OR FIRE COULD ALSO OCCUR.   DEALERS WILL INSPECT THE BATTERY CABLES FOR THE CONDITION OF THE CABLE INSULATION AND PROPER TIGHTENING OF THE TERMINAL ENDS.  AS NECESSARY, CABLES WILL BE REROUTED, RETAINING CLIPS INSTALLED, AND DAMAGED BATTERY CABLES REPLACED.   OWNER NOTIFICATION BEGAN FEBRUARY 10, 2003.   OWNERS WHO DO NOT RECEIVE THE FREE REMEDY  WITHIN A REASONABLE TIME SHOULD CONTACT FORD AT 1-866-436-7332.    ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236). 000015339000215021000000202
3   02V236000   JAYCO   FT EAGLE 10 SG  2003        EQUIPMENT:OTHER:LABELS  JAYCO, INC. 20020730    20020813    V   86  20020923    MFR Jayco, Inc. 20020904    20020912            ON CERTAIN FOLDING TENT CAMPERS, THE FEDERAL CERTIFICATION (AND RVIA) LABELS HAVE THE INCORRECT GROSS VEHICLE WEIGHT RATING, TIRE SIZE, AND INFLATION PRESSURE LISTED.  IF THE TIRES WERE INFLATED TO 80 PSI, THEY COULD BLOW RESULTING IN A POSSIBLE CRASH.    OWNERS WILL BE MAILED CORRECT LABELS FOR INSTALLATION ON THEIR VEHICLES.   OWNER NOTIFICATION BEGAN SEPTEMBER 23, 2002.    OWNERS SHOULD CONTACT JAYCO AT 1-877-825-4782.   ALSO, CUSTOMERS CAN CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236).  000015210000106403000000349

【问题讨论】:

    标签: c arrays pointers tokenize


    【解决方案1】:

    在循环内部,make[c] = token 记录了char lines[] 内部的地址。由于该缓冲区在下一次迭代中被覆盖,因此您需要将令牌复制到其他地方以确保它们的安全。

    只需使用make[c] = strdup(token)(年份也是如此)来执行此操作 - 但请记住,在任何实际程序中,您现在应该使用 free 完成所有品牌和年份字符串。

    【讨论】:

      【解决方案2】:

      当你这样做时:

      token = strtok(NULL, "\t");
      if(i==2)
      {
          make[c] = token;
      }
      

      您不获取字符串的副本,仅获取对它的指针 引用。然后下次调用fgets 时,字符串会被覆盖,所有引用都指向新字符串。因此,当您到达程序末尾时,所有指针都指向写入该内存的 last 内容。

      试试这个:

      make[c] = strdup(token);
      

      这将分配新的内存,复制字符串,并返回新的指针。副本不会被覆盖。 strdup 在内部调用 malloc,所以当你完成它时你应该 free 内存。

      【讨论】:

        【解决方案3】:

        您使用了错误的数据结构来存储结果。

        make 数组是一个指针数组。这意味着您存储的所有内容都有一个内存地址,在您的情况下,是在 strtok 操作期间使用的指针的内存地址。这不是你想要的,因为你不知道那段记忆之后会发生什么;在这种情况下,似乎在每次连续调用该函数时都会被覆盖。

        您需要使用多维数组或使用malloc()strdup() 创建由strtok() 返回的char * 值的副本。

        【讨论】:

          【解决方案4】:

          strtok 对静态缓冲区进行操作

          当你写作时

          strtok(lines, "\t");
          

          lines 缓冲区被复制到一个内部静态缓冲区 - 而 strtok 只有一个静态缓冲区 - 所以每次你的 while 循环迭代时,都会将新内容放入静态缓冲区,从而使任何先前的指针无效,即 make[] 和 year[ ].

          为了保留令牌,您需要为它们分配单独的内存,这些内存在循环结束时不会被破坏。这可以通过多种方式完成,例如在其他海报中提到的每个字符串上使用 strdup,尽管会有很多簿记然后释放内存。您还可以使用其他数据结构,例如一个链表来存储值而不是有很多指针:

          typedef struct record
          {
            char make[32]; // lets say the max length of make is 32
            char year[10];  
            struct record* next;
          } record;
          

          每当您从文件中读取新行时,都会创建一条新记录:

          record* first = NULL;
          record* last = NULL; 
          
          while (fgets(lines, sizeof(lines), fp) != NULL) 
          {
            // first create the record
            record* newRecord = malloc(sizeof(record));
            newRecord->next = NULL;
          
            // parse the line
            int column = 0;
            for (char* token = strtok(lines,"\t"); token != NULL; token = strtok(NULL, "\t"), ++column)
            {
              switch(column)
              {
              case 2: 
                strncpy(newRecord->make, token, sizeof(newRecord.make));
                break;
              case 4:
                strncpy(newRecord->year, token, sizeof(newRecord.year));
                break;
              default:  // ignore
                break;
              }
            }
            // put in the list
            if (first == NULL)
            {
              first = last = newRecord;
            }
            else
            {
              last->next = newRecord;
              last = newRecord;
            }
          }
          

          现在您有一个列表中您感兴趣的部分。你可以打印出列表

          for (record* rec = first; rec != NULL; rec = rec->next)
          {
            printf( "%s, %s\n", rec->make, rec->year );
          }
          

          // 免责声明,尚未编译。

          【讨论】:

            猜你喜欢
            • 2011-07-29
            • 2014-12-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-27
            • 2017-09-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多