从文件数据构建字符串数组时覆盖内存?

时间:2015-10-28 02:14:21

标签: c arrays pointers

这是一个家庭作业,所以我有一个限制,我不能在我的函数标题/调用中使用任何方括号(仅指针)。在函数内部,我可以使用括号作为我心中的内容。

该作业是从与出生年份相对应的文件中读取婴儿名称。该文件的组织方式使得该年份中最常见的名称是第一个,第二个下一个,等等。该文件在其上显示每个{名称,性别,使用频率},如图所示: 玛丽,女,56009

现在,我只是尝试从文件中读取这些名称,并将它们放入一个字符串数组(也就是一个char数组数组)中,以便以后进行排序。不幸的是,我得到了非常奇怪的结果。到目前为止,我已经能够将其操纵为:

正确地增加num_names var但是当它工作时它会不断地替换列表开头的名称,而不是将它添加到下一个可用的char数组(正如我想要的那样)。

OR

将名称正确设置为正确的指针但是当这种情况有效时,我的num_name计数器将不会超过num_name = 1。

我不确定为什么这两个是这样的互动。我认为我误解了一些关于记忆的事情。我去过一个导师和我的导师,并试图实施他们的建议,但它总是让我回到同样的问题。我已经在下面发布了我到目前为止的所有代码。但是,我目前使用的唯一功能是(除了主要)

readAllFiles

READFILE

processName

的GetFile

和compareStrings。

  • 我尝试将数组作为指针(*)传递,并作为指向指针(**)的指针,并以任何方式得到类似的结果。

  • 我有很多用于调试的打印语句 - 这些都不是最终执行所必需的。

问题:我的指针/字符串数组错误地导致内存覆盖了什么?

更新:我现在可以在2-D数组中正确读取名称,并且我的num_names可以同时递增。我遇到的问题是我分配内存不正确或根本没有。我使用for循环来遍历我的2-D数组并分配行和列,这似乎有助于覆盖。但是,它现在只读取第一个文件并停在第二个文件的第一个通道。更新了以下代码。

更新2:这是所有不正确的内存分配。请参阅下面的最终代码它适用于我试图解决的问题。 代码:

    /**********************************************************************************
 * Most Popular Names -
 * This program examines baby name data contained in text files from the
 * years 1920, 1930, ..., 2010 (stored as name,sex,frequency) and
 * generates an excel file containing all female names that were
 * within the top 100 names for one of those years. The file will be organized
 * as follows :
 *
 * NAME : | 1920 | 1930 | ... | 2010 |
 * Ann    |  5   |  4   | ... |  1   |
 * Beth   |  1   |  2   | ... |  5   | etc.
 *
 * *********************************************************************************
 */

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

#define MAX_NAME_LNGTH 16
#define MAX_NUM_NAMES 100
#define YEARS 10
#define FILE_1 "yob1920.txt"
#define FILE_2 "yob1930.txt"
#define FILE_3 "yob1940.txt"
#define FILE_4 "yob1950.txt"
#define FILE_5 "yob1960.txt"
#define FILE_6 "yob1970.txt"
#define FILE_7 "yob1980.txt"
#define FILE_8 "yob1990.txt"
#define FILE_9 "yob2000.txt"
#define FILE_10 "yob2010.txt"
#define OUTPUT_FILE "summary.txt"

 /* FUNCTION PROTOTYPES: */
/************************/


int readAllFiles(char **, int *, int); // called in main().

FILE *  getFile(const int); // called in readAllFiles().

int readFile(FILE *, char **, int *, int,  int ); // called in readAllFiles().

int processName(char *, int, char **, int *, int,  int); // called in readFile().

int compareStrings(char *, char *); // called in processName() and charQuickSort().

void quickSort(char ** , int *,  int ); // called in main().

// called in quickSort(arg1, arg2) for recursion.
void charQuickSort(char * , int * , char * , char * , int * , int *,  int );

void writeSummary(FILE *, char *, int *,  int ); // called in main().



   int main(void) {
    printf("begin : \n");
    int  ** all_ranks;
    int * rank_data;
    int num_names = 0;
    char * name_data;
    char ** all_names;

    name_data = malloc(MAX_NUM_NAMES * MAX_NAME_LNGTH * YEARS);
    all_names = malloc(MAX_NUM_NAMES * YEARS * sizeof(*all_names));

    rank_data = malloc(MAX_NUM_NAMES * YEARS);
    all_ranks = malloc(MAX_NUM_NAMES * YEARS * sizeof(*all_ranks));

    int i;
    for(i = 0; i < MAX_NUM_NAMES * YEARS; i++) {
        all_names[i] = &name_data[i * MAX_NAME_LNGTH];
        all_ranks[i] = &rank_data[i * YEARS];
    }

    if (all_ranks != NULL && all_names != NULL) {
        printf("in main\n");
        printf("calling read all : \n\n");
        num_names += readAllFiles(all_names, all_ranks, num_names);

    //  printf("in main\n");
    //  printf("calling quicksort : \n\n");
    //  quickSort(all_names, all_ranks, &num_names);

        printf("in main\n");
//      printf("opening file and calling write summ : \n\n");
//      FILE * output = fopen(OUTPUT_FILE, "w");
//      writeSummary(output, (char **) all_names, (int *) all_ranks, num_names);
//      fclose(output);
    }

    free(rank_data);
    free(all_ranks);
    free(all_names);
    free(name_data);
    return 0;
}

/**********************************************************************
 * Accepts a pointer for list of names and a pointer to
 * the list of ranks to be used for the 2 - D arrays
 * to hold the file(s) data.
 *
 * PARAMETERS :
 * ************
 *
 * the_names - the pointer to the list of names.
 *
 * the_ranks - the pointer to the list of ranks parallel
 * to the names.
 *
 * returns the size of the list when the files have all been
 * processed.
 *
 **********************************************************************
 */
int readAllFiles(char ** the_names, int * the_ranks, int num_names) {

    printf("in read all\n");
    /* For indexing through the files. */
    int file_num;

    /*
     * For each file in the array of file names process the file
     * and add the names and ranks to the appropriate lists.
     */
    for(file_num = 0; file_num < YEARS; file_num++) {
        printf("in for loop in read all\n file number : ");
        printf(" %d \n", file_num);
        FILE * file = getFile(file_num);
        if(file == NULL){
            perror("cannot open file");
            exit(EXIT_FAILURE);
        } else {
            printf("else : FILE OPENED.\n\n");
            num_names = readFile(file, the_names, the_ranks, file_num, num_names);
            printf("NUM_NAMES in read all : %d\n", num_names);
        }
        printf("file_num is : %d \n", file_num);
    }
    return num_names;
}

/*******************************************************
 * Gets the appropriate file for analysis.
 *
 * PARAMETERS :
 * ************
 *
 * file - the file pointer for opening.
 *
 * file_num - the number corresponding to the file
 * in need of opening.
 *******************************************************
 */
FILE * getFile(const int file_num) {
    FILE * file;
    printf("in get file. file num : \n");
    switch (file_num) {
        case 0 :
            printf("1\n");
            file = fopen(FILE_1, "r");
            break;
        case 1 :
            printf("2\n");
            file = fopen(FILE_2, "r");
            break;
        case 2 :
            printf("3\n");
            file = fopen(FILE_3, "r");
            break;
        case 3 :
            printf("4\n");
            file = fopen(FILE_4, "r");
            break;
        case 4 :
            printf("5\n");
            file = fopen(FILE_5, "r");
            break;
        case 5 :
            printf("6\n");
            file = fopen(FILE_6, "r");
            break;
        case 6 :
            printf("7\n");
            file = fopen(FILE_7, "r");
            break;
        case 7 :
            printf("8\n");
            file = fopen(FILE_8, "r");
            break;
        case 8 :
            printf("9\n");
            file = fopen(FILE_9, "r");
            break;
        case 9 :
            printf("10\n");
            file = fopen(FILE_10, "r");
            break;
        default :
            printf("null\n");
            file = NULL;
            break;
    }
    return file;
}

/**********************************************************************
 * Accepts a pointer to a file,  a pointer to
 * the list of names gathered so far, a pointer to
 * the list of ranks, and the year (0-9) to which the file
 * corresponds.
 *
 * PARAMETERS :
 * ************
 * this_file - the file containing the names and ranks.
 *
 * the_names - the list of names gathered so far.
 *
 * the_ranks - the list of ranks parallel to the names.
 *
 * the_year - the year for which the file was created.
 *
 * list_size - the amount of names so far contained in the list.
 *
 * returns the current number of names in the list.
 *
 **********************************************************************
 */
int readFile(FILE * this_file, char ** the_names, int * the_ranks, int year, int num_names) {
    /*
     * PARDON THE MESS... STILL DEBUGGING.
     */
    printf("in read file \n");
    /*
     * For ranks 0 - 99 in the file
     * get the names associated with
     * the ranks and process them.
     */
    int rank;
    for(rank = 0; rank < MAX_NUM_NAMES; rank++) {
        printf("in read file for loop \n");
        char name_temp[MAX_NAME_LNGTH];
        char read_line[MAX_NAME_LNGTH * 2];
        int name_length = 0;

        fgets(read_line, MAX_NAME_LNGTH * 2, this_file);
        printf("LINE : %s\n", read_line);

        while(read_line[name_length] != ',') {
            name_temp[name_length] = read_line[name_length];
            name_length++;
        }
        while(name_length < MAX_NAME_LNGTH){
            name_temp[name_length] = '\0';
            name_length++;
        }
        printf("NAME : %s\n", name_temp);
        printf(" NUM NAMES : %d \n", num_names);
        if (num_names) printf("BEGINNING OF NAMES (in read_file) : %s \n", the_names[0]);

        // if the name was not already in the list, will increase the size variable.
        num_names = processName(name_temp, rank + 1, the_names, the_ranks, year, num_names);
    }
    fclose(this_file);
    return num_names;
}

/**********************************************************************
 * Accepts a pointer to a single name, the rank
 * at which this name was found, a pointer to
 * the list of names gathered so far, a pointer to
 * the list of ranks, and the year (0-9) in which the
 * name was found (for proper indexing in the rank list).
 *
 * PARAMETERS :
 * ************
 *
 * this_name - the name that must be processed.
 *
 * the_rank - the rank at which the name was found.
 *
 * name_list - the list of names gathered so far.
 *
 * rank_list - the list of ranks parallel to the names.
 *
 * year - the year in which the name was found at the
 * given rank.
 *
 * list_size - the amount of names so far contained in the list.
 *
 * returns 0 if the name was already in the list and some num > 0
 * if it was not in the list.
 *
 **********************************************************************
 */
int processName(char *this_name, int the_rank,char **the_names, int * rank_list, int year, int num_names) {

    int i = 0;
    printf("this name is %s\n", this_name);
    while(this_name[i]) {
        the_names[num_names][i] = this_name[i];
        i++;
    }
    printf("attempt to assign this name to the end of the_names\n");
    printf(" the names is now %s\n", the_names[num_names]);
    num_names++;
    return num_names;
}

/********************************************************************
 * Sorts the names into alphabetical order by first calling
 * a recursive version of this function using the values
 * defined herein.
 *
 * PARAMETERS :
 * *************
 * the_names - the list of names to be sorted.
 *
 * the_ranks - the parallel (to the names) array of ranks.
 *
 * list_size - the size of the list being sorted.
 ********************************************************************
 */
void quickSort(char ** the_names, int * the_ranks, int list_size) {
    char ** names_bck = &the_names[(MAX_NAME_LNGTH *  list_size) - 1];
    int ** ranks_bck = &the_ranks[(sizeof (int) *  list_size) - 1];
    charQuickSort(the_names, the_ranks, the_names, names_bck, the_ranks, ranks_bck, &list_size);
}

/********************************************************************
 * Sorts the name array into alphabetical order using
 * the quick sort method.
 *
 * PARAMETERS :
 * *************
 *
 * names - the pointer to the 2 - D array of names.
 *
 * ranks - the pointer to the 2 - D array of ranks.
 *
 * name_frnt - the pointer to the front of the list of names.
 *
 * name_bck - the pointer to the back of the list of names.
 *
 * ranks_frnt - the pointer to the front of the list of ranks.
 *
 * ranks_bck - the pointer to the back of the list of ranks.
 * ******************************************************************
 */
void charQuickSort(char * names, int * ranks, char * name_frnt, char * name_bck, int * ranks_frnt, int * ranks_bck, int size) {
    // copy pointers to the back and front of the lists.
    char ** tmpName_frnt = name_frnt;
    char ** tmpName_bck = name_bck;

    int ** tmpRank_front = ranks_frnt;
    int ** tmpRank_back = ranks_bck;

    // pointer variables for holding names during swaps.
    char ** swap_char = NULL;
    int ** swap_int = NULL;

    // loop control variable.
    char test;

    // find a midpoint for testing
    while(tmpName_frnt < tmpName_bck) {
        name_frnt++;
        name_bck--;
    }
    //loop control variable containing the value at the end of the list.
    test = * name_bck;

    // Set temporary pointers to traverse the list of names.
    tmpName_frnt = name_frnt;
    tmpName_bck = name_bck;

    // Set temporary pointers to traverse the list of ranks.
    tmpRank_front = ranks_frnt;
    tmpRank_back = ranks_bck;

    /*
     * Do the following while the temporary pointer to the front
     * of names list is less than the temporary pointer to the
     * end of the names list.
     */
    do {
        /*
         * While the temporary pointer to the front of the names list is less than or equal to
         * the end of the names list and the value at the temporary pointer is less than the value
         * at the middle of the names list increment the temporary names and ranks.
         */
        while(tmpName_frnt <= names + (MAX_NUM_NAMES * MAX_NAME_LNGTH)
                                                && ** tmpName_frnt < test) {
            tmpName_frnt += MAX_NAME_LNGTH, tmpRank_front++;
        }

        /*
         * While the temporary pointer to the back of the names list is greater than or equal to
         * the front of the names list and the value at the temporary pointer is greater than the value
         * at the middle of the names list decrement the temporary names and ranks.
         */
        while( tmpName_bck >= names && ** tmpName_bck > test) {
            tmpName_bck -= MAX_NAME_LNGTH, tmpRank_back--;
        }

        /*
         * If the first name is greater than the second
         * (closer to Z or z), swap the pointers.
         */
        if(compareStrings(*tmpName_frnt, *tmpName_bck) > 0) {
            ** swap_char = ** tmpName_frnt;
            ** swap_int = ** tmpRank_front;
            ** tmpName_frnt = ** tmpName_bck;
            ** tmpRank_front = ** tmpRank_back;
            ** tmpName_bck = ** swap_char;
            ** tmpRank_back = ** swap_int;
            tmpName_frnt += MAX_NAME_LNGTH;
            tmpRank_front++;
            tmpName_bck -= MAX_NAME_LNGTH;
            tmpRank_back--;
        }
    } while( tmpName_frnt <= tmpName_bck);
    // Choose recursive call :
    if(name_frnt < tmpName_bck) charQuickSort(names, ranks, name_frnt, tmpName_bck, ranks_frnt, tmpRank_back, size);
    if(tmpName_frnt < name_bck) charQuickSort(names, ranks, tmpName_frnt, name_bck, tmpRank_front, ranks_bck, size);
}

/* ************************************************************************
 * Compares two strings for equality. Returns a negative value if
 * the first name is less than the second, 0 if they are equal, and
 * a positive number if the first > second.
 *
 * PARAMETERS :
 * *************
 *
 * name_1  - the first name for comparison.
 *
 * name_2 - the second name for comparison.
 *
 * RETURNS :
 * **********
 *
 * a negative value if name_1 < name_2 (name_1 nearer to A or a), 0 if
 * name_1 == name_2, and a positive value if name_1 > name_2
 * (name_1 nearer to Z or z).
 * *************************************************************************
 */
int compareStrings(char * name_1, char * name_2) {
    while(* name_1 == * name_2 && * name_1  ) {
        name_1++;
        name_2++;
    }
    return (int) (* name_1 )- (int) (* name_2);
}

/******************************************************************
 * Writes the summary data to a .csv file for output to excel.
 *
 * PARAMETERS :
 * *************
 *
 *******************************************************************
 */
void writeSummary(FILE * the_file, char * the_names, int * the_ranks, int size) {

    if(the_file == NULL) {
        perror("in write summary");
        perror("cannot open file");
        exit(EXIT_FAILURE);
    } else {

        char barrier[1] = ",";
        int **  rank = the_ranks;
        int index, name_lngth, count;
        for(index = 0; index < size; index++) {
            char ** temp = the_names + (index * MAX_NAME_LNGTH);
            while(** temp) {
                name_lngth++;
            }
            rank = rank + index;
            fwrite(temp, sizeof ** temp, name_lngth, the_file);
            for(count = 0; count < 10; count++) {
                fwrite(barrier, sizeof barrier, 1, the_file);
                fwrite(rank, sizeof (int), 1, the_file);
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

代码错误计算ranks_bck

指针算术再次出现。无需按sizeof (int)进行缩放,因为指针算术会这样做。

void quickSort(char ** the_names, int * the_ranks, int list_size) {
    char ** names_bck = &the_names[(MAX_NAME_LNGTH *  list_size) - 1];

    // int ** ranks_bck = &the_ranks[(sizeof (int) *  list_size) - 1];
    int ** ranks_bck = &the_ranks[list_size - 1];
    ...
}
OP有许多问题 - 这是一个问题。