释放字符串数组的函数

Function for freeing array of strings

在我的程序中,我有一个名为 freeFx() 的函数;

此函数被提供给两个数组和要释放的记录数。

调用此函数时出现无效指针错误。我不太明白这个错误是从哪里来的,任何帮助都会很棒!

代码如下:

/* ---- LIBRARIES ---- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* ---- PROTOTYPES ---- */
int readFx(char** charArr, int* intArr);

/* int sortFx(char** arr, int arg2);
int printFx(char** arr, int arg2); */

int freeFx(char** charArr, int* intArr, int cnt);
char* getToken(char arr1[], int loc);
void makeRoom(char*** t, int** z, int size);

/* ---- MAIN ---- */
int main(void)
{
    char** charPntrArr;
    int* intPntrArr;
    char* fileText;
    int iniArrSize = 10;
    int recCnt = 0;
    int i = 0;

    /* array to store addresses of arrays forming the rows */

    charPntrArr = malloc(iniArrSize * sizeof(char*));
    intPntrArr = malloc(iniArrSize * sizeof(int));

    recCnt = readFx(charPntrArr, intPntrArr);
    printf("%d\n", recCnt);

    /*sortFx(pntrArr, recCnt);
     printFx(pntrArr, recCnt); */
    freeFx(charPntrArr, intPntrArr, recCnt);

    return;
}

/* ---- FUNCTIONS ---- */

int readFx(char** charArr, int* intArr)
{
    /*
    input: csv file of string arrays
    output: count of records received
    purpose: read file, store values in array and populate pointer array
    */

    char buffer[350];
    char temp[350];
    char temp2[350];
    char*** reallocTemp;
    char* token;
    int counter;
    int subLoc = 4;
    int enrLoc = 9;
    int arrSize = 10;

    /* Clear headers */
    fgets(buffer, sizeof(buffer), stdin);

    counter = 0;

    /* While file stream is not null */
    while (fgets(buffer, sizeof(buffer), stdin) != NULL)
    {

        /* Populate array within array if pntr arr has room */
        if (counter < arrSize)
        {

            /* buffer copy*/
            strcpy(temp, buffer);
            strcpy(temp2, buffer);

            /* create array for token values*/
            charArr[counter] = malloc(10 * sizeof(char));

            /* Get first token */
            token = getToken(temp, subLoc);

            strcpy(charArr[counter], token);

            /* Get second token */
            token = getToken(temp2, enrLoc);

            intArr[counter] = atoi(token);

            counter++;
        }
        else
        {
            /* Reallocate memory due to necessary expansion */
            makeRoom(&charArr, &intArr, arrSize);

            /* Realloc was successful */
            if (temp != NULL)
            {
                arrSize = arrSize * 2;

                /* Print Reallocation info */
                printf("reallocating to %d\n", arrSize);

                /* Populate values for current buffer now that you have realloc'd */

                /* buffer copy*/
                strcpy(temp, buffer);
                strcpy(temp2, buffer);

                /* create array for token values */
                charArr[counter] = malloc(10 * sizeof(char));

                /* Get first token */
                token = getToken(temp, subLoc);

                strcpy(charArr[counter], token);

                /* Get second token */
                token = getToken(temp2, enrLoc);

                intArr[counter] = atoi(token);

                counter++;
            }
            else
            {
                printf("unable to reallocate\n");
                exit(1);
            }
        }



    }
        return counter;
}

    char* getToken(char arr1[], int loc)
    {

        /*
        input: string array & location of desired string
        output: string of token at position
        purpose: grab string (char*) of certain position in given array
        */

        int loopCnt;
        char* del = ",\n";

        /* Grab first token */
        char* token = strtok(arr1, del);

        /* Loop through array to grab value at given location */
        for (loopCnt = 1; loopCnt < loc; loopCnt++)
        {
            token = strtok(NULL, del);
        }

        return token;
    }

    int freeFx(char** charArr, int* intArr, int cnt)
    {
        int i;

        printf("INSIDE FREE FX\n");
        for (i = 0; i < cnt; i++)
        { 
            printf("%d\n", i);
            free(charArr[i]);
        }
        printf("FREED ARRAYS WITHIN ARRAY\n");

        free(charArr);
        printf("CHAR ARR FREE\n");

        free(intArr);
        printf("INT ARR FREE\n");

        return 0;
    }

    void makeRoom(char*** t, int** z, int size)
    {   
        *t = (char**)realloc(*t, size * 2 * sizeof(char*));

        *z = (int*)realloc(*z, size * 2 * sizeof(int*));

    }

这是文本文件中的示例:

Term Code,Session Code,Campus Code,Subject,Catalog Nbr,Section,Class Nbr,Class Component,Enrollment Total,Enrollment Cap,Enrollment Availability,Waitlist Total,Waitlist Cap,Instructor Name,Instructor Email,Building Code,Room Nbr,Start Time,End Time,M,T,W,Th,F,Sa,Su,Class Start Date,Class End Date
2152,1,MAIN,SOCW,6390,6,22913,IND  - Independent Study,0,1,1,0,0,,,,,12:00 AM,12:00 AM,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,MUSI,4460,3,21831,PRI  - Private Lesson,0,20,20,0,0,Michael J Drake,mjdrake@uta.edu,,,12:00 AM,12:00 AM,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,MAE,4301,1,27674,LEC  - Lecture,0,5,5,0,3,,,NH,109,7:00 PM,8:20 PM,Y,N,Y,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,EE,2403,101,25557,LAB  - Laboratory,11,24,13,0,0,Jonathan W Bredow,jbredow@uta.edu,NH,148A,5:30 PM,8:20 PM,Y,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,SOCW,6451,68,26055,PRA  - Practicum,1,1,0,0,0,Laura S Frank,laura.frank@mavs.uta.edu,,,12:00 AM,12:00 AM,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,ARCH,3331,1,20182,LEC  - Lecture,47,61,14,0,0,Edward R Nelson,nelsone@uta.edu,ARCH,401,5:30 PM,6:50 PM,Y,N,Y,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,BIOL,6291,7,26391,IND  - Independent Study,0,5,5,0,0,Matthew Fujita,mkfujita@uta.edu,,,12:00 AM,12:00 AM,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,BE,6194,12,30366,IND  - Independent Study,6,6,0,0,0,Young-Tae Kim,ykim@uta.edu,,,,,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,BIOL,5698,21,27536,THE  - Thesis Research,0,5,5,0,0,Laura D Mydlarz,mydlarz@uta.edu,,,12:00 AM,12:00 AM,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,EDAD,6399,7,20089,DTN  - Dissertation,2,10,8,0,0,Daniel B Saunders,saunders@uta.edu,,,12:00 AM,12:00 AM,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,BE,3344,14,26082,LEC  - Lecture,6,10,4,0,0,Baohong Yuan,baohong@uta.edu,ERB,131,11:00 AM,12:20 PM,N,Y,N,Y,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,EDAD,6390,11,26017,LEC  - Lecture,0,10,10,0,0,Yi Zhang,lyzhang@uta.edu,,,12:00 AM,12:00 AM,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,BIOL,3454,2,20468,LAB  - Laboratory,31,30,-1,0,0,Nicholas A Long,nicholas.long@mavs.uta.edu,LS,133,1:00 PM,4:50 PM,Y,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,CHEM,1451,1,22411,LEC  - Lecture,118,140,22,0,0,Seiichiro Tanizaki,tanizaki@uta.edu,SH,121,9:00 AM,9:50 AM,Y,N,Y,N,Y,N,N,1/20/2015,5/8/2015
2152,1,MAIN,ME,6297,39,30394,IND  - Independent Study,1,5,4,0,0,Ashfaq Adnan,aadnan@uta.edu,,,,,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,MUSI,1243,2,21463,PRI  - Private Lesson,1,20,19,0,0,Young-Hyun Cho,yhcho@uta.edu,,,12:00 AM,12:00 AM,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,MUSI,4242,2,21728,PRI  - Private Lesson,0,20,20,0,0,Young-Hyun Cho,yhcho@uta.edu,,,12:00 AM,12:00 AM,N,N,N,N,N,N,N,1/20/2015,5/8/2015
2152,1,MAIN,EVSE,6399,44,25290,DTN  - Dissertation,1,5,4,0,0,Merlynd K Nestell,nestell@uta.edu,,,12:00 AM,12:00 AM,N,N,N,N,N,N,N,1/20/2015,5/8/2015

检查 readFx 的 return 值。

post 整个功能可能会更容易。也许计数器不是从 0

开始

据我所知,除了一般代码的脆弱性(我会更改很多)之外,最大的问题是您传递给 reader 函数的按值数组。

您最初在此处调整大小 main():

charPntrArr = malloc(iniArrSize * sizeof(char*));
intPntrArr = malloc(iniArrSize * sizeof(int)); // note: fixed this. also fix in your resize fn

然后它们的(每个指针持有的地址)被传递到你的reader这里:

recCnt = readFx(charPntrArr, intPntrArr);

在不同的时间,reader 可以(并且确实)调整这些缓冲区的大小,包括在需要时重新定位数据。不能保证基地址保持不变。因此,当 readFX returns 时,指针仍保持原始值,但调整大小的努力早已使这些位置不再定义为可访问。

解决此问题的快速方法是执行以下操作:

  • 更改您的 readFX 函数以按地址获取其指针参数(指向指针的指针)。
  • 在实际函数中重命名输入参数(看到下面的代码就会明白)
  • 声明具有相同原始名称的局部变量,并使用参数的解除引用初始值进行初始化。
  • 函数完成后将局部变量保存回取消引用的参数。

像这样:

int readFx(char*** ppCharArr, int** ppIntArr)
{
    char **charArr = *ppCharArr;
    int *intArr = *ppIntArr;

    /*
     input: csv file of string arrays
     output: count of records received
     purpose: read file, store values in array and populate pointer array
     */

    char buffer[350];
    char temp[350];
    char* token;
    int counter;
    int subLoc = 4;
    int enrLoc = 9;
    int arrSize = 10;


    counter = 0;

    /* Clear headers */
    fgets(buffer, sizeof(buffer), stdin);

    /* While file stream is not null */
    while (fgets(buffer, sizeof(buffer), stdin) != NULL)
    {

        /* Populate array within array if pntr arr has room */
        if (counter >= arrSize)
        {
            /* Reallocate memory due to necessary expansion */
            arrSize = makeRoom(&charArr, &intArr, arrSize);

            /* Realloc was successful */
            if (charArr == NULL || intArr == NULL)
            {
                printf("unable to reallocate\n");
                exit(1);
            }
        }

        /* buffer copy*/
        strcpy(temp, buffer);

        /* Get first token */
        token = getToken(buffer, subLoc);
        if (token != NULL)
            charArr[subLoc] = strdup(token);

        /* Get second token */
        token = getToken(temp, enrLoc);
        intArr[counter] = atoi(token);

        counter++;

    }

    *ppCharArr = charArr;
    *ppIntArr = intArr;
    return counter;
}

像这样从 main() 调用:

charPntrArr = malloc(iniArrSize * sizeof *charPntrArr);
intPntrArr = malloc(iniArrSize * sizeof *intPntrArr);
recCnt = readFx(&charPntrArr, &intPntrArr);

freeFX 调用可以保持原样。这是我能为您解决此特定问题的最快方法。 注意: 我对这段代码进行了一些修改,所以有些东西无法通过简单的 cut/paste 返回到您的代码库(我已经 makeRoom 返回例如,新尺寸),但您仍然可以看到根本问题是什么。

希望对您有所帮助。


更新

一个精简版,在读取数组和内容的冒泡排序中集成了分配。我希望 OP 觉得它有用。恕我直言,这比原始版本要干净得多。

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

/* ---- PROTOTYPES ---- */
int readFx(char*** ppCharArr, int** ppIntArr);
int freeFx(char** charArr, int* intArr, int cnt);
void sortFx(char** const charArr, int* const intArr, int cnt);

/* ---- MAIN ---- */
int main(void)
{
    char** charPntrArr = NULL;
    int* intPntrArr = NULL;
    int recCnt = 0;

    /* array to store addresses of arrays forming the rows */

    /* read file and get record count */
    recCnt = readFx(&charPntrArr, &intPntrArr);
    sortFx(charPntrArr, intPntrArr, recCnt);
    freeFx(charPntrArr, intPntrArr, recCnt);
}

/* ---- FUNCTIONS ---- */

int readFx(char*** ppCharArr, int** ppIntArr)
{
    const int subLoc = 4;
    const int enrLoc = 9;

    char **charArr = *ppCharArr;
    int *intArr = *ppIntArr;

    char line[350];
    char* token = NULL;
    int arrSize = 0;
    int counter = 0;
    int i=0;

    /* Clear headers */
    fgets(line, sizeof(line), stdin);
    while (fgets(line, sizeof(line), stdin) != NULL)
    {
        // check for reallocation prior to insertion
        if (counter == arrSize)
        {
            // need to expand
            int newSize = (arrSize ? (2*arrSize) : 1);
            void *tmp = realloc(charArr, newSize * sizeof *charArr);
            if (tmp == NULL)
            {
                fprintf(stderr, "Failed to expand charArr to %d elements", newSize);
                exit(1);
            }
            charArr = tmp;

            // expand intArr likewise
            tmp = realloc(intArr, newSize * sizeof(*intArr));
            if (tmp == NULL)
            {
                fprintf(stderr, "Failed to expand intArr to %d elements", newSize);
                exit(1);
            }
            intArr = tmp;
            arrSize = newSize;

            printf("Resized arrays to %d slots\n", newSize);
        }

        // get tokens
        for (token = strtok(line, ",\n"), i=1; token && (i<subLoc); ++i)
            token = strtok(NULL, ",\n");
        if (token)
        {
            charArr[counter] = strdup(token);

            // next token
            for (; token && i<enrLoc; ++i)
                token = strtok(NULL, ",\n");
            if (token)
            {
                intArr[counter] = atoi(token);
                printf("%s %d\n", charArr[counter], intArr[counter]);
                ++counter;
            }
            else
            {
                free(charArr[counter]);
            }
        }

    }

    *ppCharArr = charArr;
    *ppIntArr = intArr;

    return counter;
}

int freeFx(char** charArr, int* intArr, int cnt)
{
    while (cnt--)
        free(charArr[cnt]);
    free(charArr);
    free(intArr);
    return 0;
}


void sortFx(char** const charArr, int* const intArr, int cnt)
{
    int swapped = 1, i, j=cnt;

    // simple bubblesort algorithm. note there is no string copying cone here
    //  we compare strings, and if swapping is needed, swap *pointers* in the
    //  charArr pointer array (and intArr side by side, but that is unrelated)
    while (swapped && j--)
    {
        swapped = 0; // reset swap detection

        for (i = 0; i < j; ++i)
        {
            int cmp = strcmp(charArr[i], charArr[i+1]);
            if ( cmp > 0)
            {
                char *strTmp = charArr[i];
                int intTemp = intArr[i];

                // do the swaps
                charArr[i] = charArr[i+1];
                charArr[i+1] = strTmp;
                intArr[i] = intArr[i+1];
                intArr[i+1] = intTemp;

                // something swapped so set flag
                swapped = 1;
            }
            else if (cmp == 0 && intArr[i] > intArr[i+1])
            {
                int intTemp = intArr[i];
                intArr[i] = intArr[i+1];
                intArr[i+1] = intTemp;

                // something swapped so set flag
                swapped = 1;
            }
        }
    }

    printf("\nSORTED RESULTS\n");
    for (i=0; i<cnt; ++i)
        printf("%s %d\n", charArr[i], intArr[i]);
}

输出

以下输出来自粘贴的样本数据。

Resized arrays to 1 slots
SOCW 0
Resized arrays to 2 slots
MUSI 0
Resized arrays to 4 slots
MAE 0
EE 11
Resized arrays to 8 slots
SOCW 1
ARCH 47
BIOL 0
BE 6
Resized arrays to 16 slots
BIOL 0
EDAD 2
BE 6
EDAD 0
BIOL 31
CHEM 118
ME 1
MUSI 1
Resized arrays to 32 slots
MUSI 0
EVSE 1

SORTED RESULTS
ARCH 47
BE 6
BE 6
BIOL 0
BIOL 0
BIOL 31
CHEM 118
EDAD 0
EDAD 2
EE 11
EVSE 1
MAE 0
ME 1
MUSI 0
MUSI 0
MUSI 1
SOCW 0
SOCW 1