【问题标题】:Array changing first value without explicitly modifying it when calling fscanf调用 fscanf 时数组更改第一个值而不显式修改它
【发布时间】:2011-11-18 04:39:40
【问题描述】:

我正在从 std in 读取一个值并将其存储在数组 min[3] 中,然后继续进行数组比较。所以min在比较之前是不会被触及的。

调试后,我注意到min[0]在执行这一行时从输入值变为\0

fscanf(locDayFile, "%s", extractedHour);

locDayFileextractedHour 声明如下:

FILE* locDayFile;
char extractedHour[3];

对出了什么问题有任何想法吗?

编辑我在这里发布代码:

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

struct coords{
    float coord[3];
    char station[5];
    struct coords *next;
};

void Add(struct coords**,char*, float*);
float* Get(struct coords*, char*);

int main(){

    DIR *rootFolder, *subFolder;
    struct dirent *rootEnt, *subEnt;
    char rootFolderName[260], subFolderName[260];

    FILE *locDayFile,  *headers, *coordFile;
    FILE *stationDay, *yearDay, *time, *reference;
    char locDayFileName[260], headersFileName[260], coordFileName[260];
    char stationDayName[260], yearDayName[260], timeName[260], referenceName[260];
    char result[260];
    char make[260];

    char readLine[256];

    char searchingFolderName[9], folderCmp[9];

    char location[7], year[5], day[4], hour[3], min[3], referenceStation[5];
    char locationTest[7], dayTest[4];
    char extractedStation[5], extractedYear[5], extratedDay[4], extractedHour[3], extractedMin[3];
    char rms[7];
    float delay, refereDelay = 0;
    float *coordinates;

    char choice;

    printf("Please enter the following information:\n");
    printf("Location: ");
    scanf("%s", location);
    memmove(location+1, location, 4);
    location[0] = 'o';
    location[5] = 'a';
    location[6] = '\0';
    printf("Year: ");
    scanf("%s", year);
    printf("Day: ");
    scanf("%s", day);

    sprintf(searchingFolderName, "%s_%s", year, day);

    hour[0] = '\0';
    min[0] = '\0';
    referenceStation[0] = '\0';
    referenceName[0] = '\0';
    printf("Do you wish to enter the time?(Y/N): ");
    do{
        scanf("%c", &choice);
    }while(choice != 'Y' && choice != 'y' && choice != 'N' && choice != 'n');
    if(choice == 'Y' || choice == 'y'){
        printf("Hour: ");
        scanf("%s", hour);
        printf("Minutes: ");
        scanf("%s", min);
    }
    printf("Do you wish to enter a reference station?(Y/N): ");
    do{
        scanf("%c", &choice);
    }while(choice != 'Y' && choice != 'y' && choice != 'N' && choice != 'n');
    if(choice == 'Y' || choice == 'y'){
        printf("Reference station: ");
        scanf("%s", referenceStation);
    }

    printf("Root folder path: ");
    scanf("%s", rootFolderName);

    struct coords *c;
    c = NULL;

    printf("Coordinates file path: ");
    scanf("%s", coordFileName);
    coordFile = fopen(coordFileName, "r");
    if(coordFile != NULL){
        char st[5];
        float coords[3];
        while(!feof(coordFile)){
            fscanf(coordFile, "%s", st);
            fscanf(coordFile, "%f", &coords[0]);
            fscanf(coordFile, "%f", &coords[1]);
            fscanf(coordFile, "%f", &coords[2]);

            Add(&c, st, coords);
        }
    }

    if((rootFolder = opendir(rootFolderName)) != NULL){
        while((rootEnt = readdir(rootFolder)) != NULL){

            sprintf(result, "%sresults/", rootFolderName);
            sprintf(make, "mkdir -p %s", result);
            system(make);

            folderCmp[0] = '\0';
            strncpy(folderCmp, rootEnt->d_name, 8);
            folderCmp[8] = '\0';

            if(strcmp(folderCmp, searchingFolderName) == 0){

                sprintf(subFolderName, "%s%s/", rootFolderName, rootEnt->d_name);

                if((subFolder = opendir(subFolderName)) != NULL){
                    while((subEnt = readdir(subFolder)) != NULL){

                        strncpy(locationTest, subEnt->d_name, 6);
                        locationTest[6] = '\0';
                        strncpy(dayTest, (subEnt->d_name)+7, 3);
                        dayTest[3] = '\0';
                        if((strcmp(location, locationTest) == 0) && (strcmp(day, dayTest) == 0)){

                            sprintf(locDayFileName, "%s%s", subFolderName, subEnt->d_name);
                            locDayFile = fopen(locDayFileName, "r");

                            while(!feof(locDayFile)){

                                char garbage[25];

                                fscanf(locDayFile, "%s", garbage);
                                if(strcmp(garbage, "ATM_ZEN") == 0){

                                    sprintf(headersFileName, "%sheaders_%s-%s", rootFolderName, year, day);
                                    headers = fopen(headersFileName, "a+");

                                    fscanf(locDayFile, "%s", garbage);

                                    fscanf(locDayFile, "%s", extractedStation);//3rd column.
                                    fprintf(headers, "%s\t", extractedStation);

                                    fscanf(locDayFile, "%s", garbage);

                                    fscanf(locDayFile, "%s", extractedYear);//5th column.
                                    fprintf(headers, "%s\t", extractedYear);

                                    fscanf(locDayFile, "%s", garbage);

                                    fscanf(locDayFile, "%s", extratedDay);//7th column.
                                    fprintf(headers, "%s\t", extratedDay);

                                    fscanf(locDayFile, "%s", extractedHour);//8th column.
                                    fprintf(headers, "%s\t", extractedHour);

                                    fscanf(locDayFile, "%s", extractedMin);//9th column.
                                    fprintf(headers, "%s\t", extractedMin);

                                    fscanf(locDayFile, "%s", garbage);
                                    fscanf(locDayFile, "%s", garbage);

                                    fscanf(locDayFile, "%f", &delay);//12th column.
                                    fscanf(locDayFile, "%s", rms);//13 column.
                                    fprintf(headers, "%s\t", rms);
                                    fprintf(headers, "%f\n", delay);

                                    if(strcmp(referenceStation, extractedStation) == 0 && refereDelay == 0)
                                        refereDelay = delay;


                                    coordinates = Get(c, extractedStation);
                                    if(coordinates != NULL){
                                        //station_day file
                                        sprintf(stationDayName, "%s%s_%s", result, extractedStation, extratedDay);
                                        stationDay = fopen(stationDayName, "a+");
                                        fprintf(stationDay, "%s\t", extractedYear);
                                        fprintf(stationDay, "%s\t", extractedHour);
                                        fprintf(stationDay, "%s\t", extractedMin);
                                        fprintf(stationDay, "%f\t", coordinates[0]);
                                        fprintf(stationDay, "%f\t", coordinates[1]);
                                        fprintf(stationDay, "%f\t", coordinates[2]);
                                        fprintf(stationDay, "%s\t", rms);
                                        fprintf(stationDay, "%f\n", delay);
                                        fclose(stationDay);

                                        //year_day file
                                        sprintf(yearDayName, "%s%s_%s", result, extractedYear, extratedDay);
                                        yearDay = fopen(yearDayName, "a+");
                                        fprintf(yearDay, "%s\t", extractedStation);
                                        fprintf(yearDay, "%s\t", extractedHour);
                                        fprintf(yearDay, "%s\t", extractedMin);
                                        fprintf(yearDay, "%f\t", coordinates[0]);
                                        fprintf(yearDay, "%f\t", coordinates[1]);
                                        fprintf(yearDay, "%f\t", coordinates[2]);
                                        fprintf(yearDay, "%s\t", rms);
                                        fprintf(yearDay, "%f\n", delay);
                                        fclose(yearDay);

                                        //year_day_hour_min file
                                        if((hour[0] != '\0' && (strcmp(hour, extractedHour) == 0)) && (min[0] != '\0' && (strcmp(min, extractedMin) == 0))){
                                            sprintf(timeName , "%s_%s_%s", yearDayName, hour, min);
                                            time = fopen(timeName, "a+");
                                            fprintf(time, "%s\t", extractedStation);
                                            fprintf(time, "%f\t", coordinates[0]);
                                            fprintf(time, "%f\t", coordinates[1]);
                                            fprintf(time, "%f\t", coordinates[2]);
                                            fprintf(time, "%s\t", rms);
                                            fprintf(time, "%f\n", delay);
                                            fclose(yearDay);
                                        }
[.....]

【问题讨论】:

  • 您是否致电fopen 打开文件?你检查返回值了吗?
  • @Saphrosit 是的,我是,我在打开文件后正在执行 multime fscanf 和 fprintf ...但它正在中断我在这里发布的那个,这是第 5 次调用

标签: c arrays file-io char scanf


【解决方案1】:

您没有向我们展示足够多的内容,所以这纯粹是一个猜测,但是您正在读入 extractedHour 的输入可能是三个字符长,并且您已将数组定义为 3 个字符,因此没有空间NUL 终止符。

您可能在extractedHour 之后立即定义了min,所以当您写到extractedHour 的末尾之后,它最终会将NUL 终止符写入下一个内存,恰好是min

【讨论】:

  • 1) min 被定义然后初始化......并且读取的值在接下来的 100 行中是持久的(没有显式修改 min)2)有一个 NULL 是 min[2] ...即当我在 std in 中输入 28 时,min = ['2']['8']['\0']
【解决方案2】:

对不起,我只能给出风格上的评论。

1) 分而治之:将代码分成逻辑函数,每个函数只做一件事。这也将更容易在没有太多干扰的情况下测试单独的部分。

2) feof() 没有做你认为它做的事情。

3) 如果您首先阅读整行(例如使用 fgets())然后将它们拆分为字段,那么解析文本文件会更容易。它也不太容易受到缓冲区溢出的影响。

4) gets() 是灾难的根源。你使用它的形式的 scanf() 也是如此。

【讨论】:

    【解决方案3】:

    如果没有更多信息,我的猜测是 locDayFile 包含一个超过 3 个字节的字符串。当您进行 fscanf 调用时,它会覆盖比您想象的更多的内存。尝试为extractHour 分配一个更大的缓冲区(而不是3,让它像64),让我们知道会发生什么。如果这解决了问题,您可能需要先修复您的 locDayFile,然后修复您的 fscanf 调用,而不是使用 %s,使用 %2s,这告诉 scanf(及其变体)您只希望它读取带有最多 2 个字符。这将避免缓冲区溢出。另一种选择是使用 %as... 来分配字符串(scanf 将分配存储字符串所需的字节数)。

    例子:

    char *str;
    fscanf(in_file, "%as", &str);  //Notice the & here!
    //Not covered is calling free(str)
    //But you must check if fscanf was successful
    //before freeing str
    

    示例 2:

    char str[3];
    fscanf(in_file, "%2s", str);  //Notice this doesn't use &
    //No need to deallocate, and it will not buffer overrun on you!
    

    如果这不能修复您的程序,请给我们更多信息。

    【讨论】:

      猜你喜欢
      • 2018-06-23
      • 1970-01-01
      • 2021-09-04
      • 1970-01-01
      • 1970-01-01
      • 2013-03-12
      • 1970-01-01
      • 1970-01-01
      • 2018-01-15
      相关资源
      最近更新 更多