在分配阵列C时检测到堆栈粉碎

时间:2017-04-01 04:35:11

标签: c stack-overflow

标题解释了问题。在我的程序中的这个函数中,每当我在数组中分配一定大小时,我的终端上就会收到大量的错误代码。数组被正确复制,但是在打印完成后,程序崩溃了。该程序的目的是从文件中读取,然后将每一行存储在数组索引中。非常感谢您的帮助。谢谢

数组在main中声明为指针,然后在内部动态分配。

    void read_file_into_array(char **filearray, FILE * fp)
        {
            /* use get line to count # of lines */
            int numlines = -1;
            numlines = linecount(fp);
            size_t size = 50;
            char *buffer;

            buffer = (char *)malloc(size * sizeof(char));
            if (buffer == NULL) {
                perror("Unable to allocate buffer");
                exit(1);
            }

            if (numlines < 0) {
                fprintf(stderr, "error: unable to determine file length.\n");
                return;
            }

            printf(" number of lines counted are ; %d\n", numlines);

            /* allocate array of size numlines + 1 */

            if (!(*filearray = (char *)malloc(numlines + 1 * sizeof(char)))) {
                fprintf(stderr, "error: virtual memory exhausted.\n");
                return;
            }

            fseek(fp, 0, SEEK_SET);
            for (int i = 0; i < numlines; i++) {
                if (!feof(fp)) {
                    fgets(buffer, size, fp);
                    filearray[i] = (char *)malloc(size * sizeof(char *));
                    strcpy(filearray[i], buffer);
                    printf("buffer at %d : %s\n", i, buffer);
                    printf("array at %d : %s\n", i, filearray[i]);
                }
            }
            free(buffer);
        }



        /* THIS IS MY MAIN BELOW */

        int main (int argc, char **argv)

        {
        FILE *fp = NULL;
        char*  array;

        /* open file for reading (default stdin) */
            fp = argc > 1 ? fopen (argv[1], "r") : stdin;

            if (!fp) {  /* validate file open */
                fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
                return 1;
            }

            read_file_into_array (&array, fp);

        if (fp != stdout) 
                if (fclose (fp) == EOF) {
                    fprintf (stderr, "error: fclose() returned EOF\n");
                    return 1;
                }


        return 0;
        }


    /* MY LNE COUNT FUNCITON */
    int linecount(FILE *fp) {
    char buff[MAXLINE];
    int count = 0;

    while(fgets(buff,MAXLINE,fp) != NULL) {
    count++;
    }
    return count;
}

2 个答案:

答案 0 :(得分:0)

您收到编译警告的主要问题之一(+注意指出代码中其他不同错误的注释)是

  1. if (!(*filearray = (char**)malloc(sizeof(char*) * (numlines + 1))))
  2. *filearray的类型为char*而不是char**; +,无需转换malloc返回的值。

    1. char **filearray实际上来自&array的{​​{1}},其定义为main()

    2. 现在,以下内容完全打破了稳定性并导致未定义的行为

      char *array;

      这相当于主要的filearray[i] = (char *)malloc(size * sizeof(char *)); ,这是完全打破。您正在遍历堆栈,从(&array)[i] = (char *)malloc(size * sizeof(char *));的{​​{1}}位置开始,只需覆盖array返回的main值的所有内容。

      如果您希望char*为字符串数组,将其定义为malloc,请通过指针array传递,相应地更新声明和char **array的用法。

答案 1 :(得分:0)

好的,让我们整理出来。首先,要将pointer to pointer to char作为参数传递给函数,在函数内分配并在调用函数中返回结果(不再有),必须传递 的地址指向char的指针。否则,函数会收到一个副本,并且函数中所做的任何更改都不会在调用者(main此处)中返回,因为复制丢失(分配块的起始地址丢失)回报。

将指针的地址传递给指向char的指针意味着您必须成为 3-STAR程序员(这不是恭维)。一个更好的方法是根本不传递指针,只需在函数内分配,然后返回一个指向调用者的指针(但在某些情况下,你仍然需要将它作为参数传递,所以如下所示)

下面的程序将读取作为第一个参数传递的任何文本文件(如果没有给出参数,它将从stdin读取)。它将动态分配指针并且需要(在MAXL块中而不是一次一个,这是非常低效的)。它将根据需要分配(和重新分配)行以容纳任何长度的行。它使用MAXC个字符的固定缓冲区来连续读取,直到读取完整的行,将offset保存到当前行中的位置,以根据需要附加后续读取。

最后,在读取文件后,它会将文本和关联的行号打印到stdout,并在退出之前释放所有已分配的内存。仔细看看,如果您有任何问题,请告诉我:

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

enum { MAXL = 32, MAXC = 1024 };

char **read_file_into_buf (char ***buf, FILE *fp, int *nlines);

int main (int argc, char **argv) {

    char **buf = NULL;  /* buffer to hold lines of file */
    int n;              /* number of lines read */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    if (read_file_into_buf (&buf, fp, &n)) {        /* read file into buf  */
        for (int i = 0; i < n; i++) {               /* loop over all lines */
            printf ("line[%3d]: %s\n", i, buf[i]);  /* output line */
            free (buf[i]);      /* free line */
        }
        free (buf);             /* free buffer */
    }

    if (fp != stdin) fclose (fp);     /* close file if not stdin */

    return 0;
}

/** read text file from 'fp' into 'buf' update 'nlines'.
 *  Being a 3-STAR Programmer, is NOT a compliment. However,
 *  to pass a pointer to pointer to char as a parameter and 
 *  allocate within the function, it is required. You must
 *  pass the address of buf from main otherwise the function
 *  recieves a copy whose allocation is lost on return. A better
 *  approach is to simply assign the return in 'main' and not 
 *  pass buf at all.
 */
char **read_file_into_buf (char ***buf, FILE *fp, int *nlines)
{
    /* current allocation, current index, and offset (if less 
     * than a whole line is read into line on fgets call), and
     * eol indicates '\n' present.
     */
    size_t n = MAXL, idx = 0, offset = 0, eol = 0;
    char line[MAXC] = "";   /* temp buffer for MAXC chars */
    void *tmp = NULL;       /* pointer for realloc */

    /* validate address, file ptr & nlines address */
    if (!buf || !fp || !nlines) {
        fprintf (stderr, "error; invalid parameter.\n");
        return NULL;
    }

    /* allocate initial MAXL pointers, calloc used to avoid valgrind
     * warning about basing a conditional jump on uninitialized value.
     * calloc allocates and initializes.
     */
    if (!(*buf = calloc (sizeof *buf, MAXL))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return NULL;
    }

    while (fgets (line, MAXC, fp))  /* read every line in file */
    {
        /* save offset from prior read (if any), get len */
        size_t end = offset, len = strlen (line);

        if (line[len - 1] == '\n') {    /* test for new line */
            line[--len] = 0;            /* overwrite with nul */
            offset = 0;                 /* zero offset, all read */
            eol = 1;                    /* POSIX eol present */
        }
        else {
            line[len] = 0;  /* nul-terminate */
            offset += len;  /* short read, save offset to last char */
            eol = 0;        /* no POSIX eol */
        }

        /* allocate/reallocate for current line + nul-byte */
        tmp = realloc ((*buf)[idx], sizeof ***buf * (end + len + 1));
        if (!tmp) {
            fprintf (stderr, "error: realloc, memory exhausted.\n");
            return *buf;  /* return current buf */
        }
        (*buf)[idx] = tmp;  /* assign block to current index */
        strcpy ((*buf)[idx] + end, line);  /* copy line to block */

        if (!eol) continue;   /* chars remain in line, go read them */

        if (++idx == n) {   /* check pointer allocation, realloc as needed */
            tmp = realloc (*buf, sizeof **buf * (n + MAXL));
            if (!tmp) {
                fprintf (stderr, "error: realloc buf, memory exhausted.\n");
                return *buf;
            }
            *buf = tmp; /* assign new block to *buf */
            memset (*buf + n, 0, sizeof **buf * MAXL);  /* zero new memory */
            n += MAXL;  /* update the current number of ptrs allocated */
        }
        *nlines = idx;  /* update the number of lines read */
    }
    if (!eol) {         /* protect against file with no POSIX ending '\n' */
        idx++;          /* account for final line */
        *nlines = idx;  /* update nlines */
    }

    /* final realloc to size buf to exactly fit number of lines */
    tmp = realloc (*buf, sizeof **buf * (idx));
    if (!tmp)   /* if it fails, return current buf */
        return *buf;

    *buf = tmp; /* assign reallocated block to buf */

    return *buf;
}

注意:将使用memset (*buf + n, 0, sizeof **buf * MAXL);分配的新指针归零是可选的,但它会消除valgrind有关基于未初始化值的条件跳转的警告,就像使用{{ 1}}的初始指针。 calloc/malloc无法选择归零,因此需要单独调用realloc

示例使用/输出

memset

在你编写的动态分配内存的任何代码中,你有2个职责关于任何分配的内存块:(1)总是保留一个指向起始地址的指针内存块,(2)当不再需要时,它可以释放

您必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,尝试读取或基于未初始化的值跳转,最后确认您已拥有释放了你分配的所有内存。

对于Linux $ ./bin/fgets_readfile < dat/damages.txt line[ 0]: Personal injury damage awards are unliquidated line[ 1]: and are not capable of certain measurement; thus, the line[ 2]: jury has broad discretion in assessing the amount of line[ 3]: damages in a personal injury case. Yet, at the same line[ 4]: time, a factual sufficiency review insures that the line[ 5]: evidence supports the jury's award; and, although line[ 6]: difficult, the law requires appellate courts to conduct line[ 7]: factual sufficiency reviews on damage awards in line[ 8]: personal injury cases. Thus, while a jury has latitude in line[ 9]: assessing intangible damages in personal injury cases, line[ 10]: a jury's damage award does not escape the scrutiny of line[ 11]: appellate review. line[ 12]: line[ 13]: Because Texas law applies no physical manifestation line[ 14]: rule to restrict wrongful death recoveries, a line[ 15]: trial court in a death case is prudent when it chooses line[ 16]: to submit the issues of mental anguish and loss of line[ 17]: society and companionship. While there is a line[ 18]: presumption of mental anguish for the wrongful death line[ 19]: beneficiary, the Texas Supreme Court has not indicated line[ 20]: that reviewing courts should presume that the mental line[ 21]: anguish is sufficient to support a large award. Testimony line[ 22]: that proves the beneficiary suffered severe mental line[ 23]: anguish or severe grief should be a significant and line[ 24]: sometimes determining factor in a factual sufficiency line[ 25]: analysis of large non-pecuniary damage awards. 是正常的选择。

valgrind

始终确认释放所有堆块 - 不可能泄漏并且同样重要错误摘要:0个上下文中的0个错误。 (虽然注意:某些操作系统没有提供足够的记忆排除文件(排除系统和操作系统内存不被报告为正在使用的文件),这将导致$ valgrind ./bin/fgets_readfile < dat/damages.txt ==5863== Memcheck, a memory error detector ==5863== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==5863== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==5863== Command: ./bin/fgets_readfile ==5863== line[ 0]: Personal injury damage awards are unliquidated line[ 1]: and are not capable of certain measurement; thus, the line[ 2]: jury has broad discretion in assessing the amount of line[ 3]: damages in a personal injury case. Yet, at the same line[ 4]: time, a factual sufficiency review insures that the line[ 5]: evidence supports the jury's award; and, although line[ 6]: difficult, the law requires appellate courts to conduct line[ 7]: factual sufficiency reviews on damage awards in line[ 8]: personal injury cases. Thus, while a jury has latitude in line[ 9]: assessing intangible damages in personal injury cases, line[ 10]: a jury's damage award does not escape the scrutiny of line[ 11]: appellate review. line[ 12]: line[ 13]: Because Texas law applies no physical manifestation line[ 14]: rule to restrict wrongful death recoveries, a line[ 15]: trial court in a death case is prudent when it chooses line[ 16]: to submit the issues of mental anguish and loss of line[ 17]: society and companionship. While there is a line[ 18]: presumption of mental anguish for the wrongful death line[ 19]: beneficiary, the Texas Supreme Court has not indicated line[ 20]: that reviewing courts should presume that the mental line[ 21]: anguish is sufficient to support a large award. Testimony line[ 22]: that proves the beneficiary suffered severe mental line[ 23]: anguish or severe grief should be a significant and line[ 24]: sometimes determining factor in a factual sufficiency line[ 25]: analysis of large non-pecuniary damage awards. ==5863== ==5863== HEAP SUMMARY: ==5863== in use at exit: 0 bytes in 0 blocks ==5863== total heap usage: 28 allocs, 28 frees, 1,733 bytes allocated ==5863== ==5863== All heap blocks were freed -- no leaks are possible ==5863== ==5863== For counts of detected and suppressed errors, rerun with: -v ==5863== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 报告有些记忆尚未被释放(尽管你已经完成了自己的工作并释放了你分配并在你控制下的阻止。)