简体   繁体   English

Valgrind使用动态数组和结构C进行内存泄漏

[英]Valgrind memory leak with dynamic arrays and structs C

I have problem with my code. 我的代码有问题。 Code compiles and runs without warnings or errors and does that I wanted, but Valgrind finds memory leaks that I couldn't repair. 代码编译并在没有警告或错误的情况下运行,并且我想要这样做,但Valgrind找到了我无法修复的内存泄漏。 I was unable to correct code myself for several days. 我好几天都无法自己纠正代码。 Can you please point out that I am doing wrong? 你能指出我做错了吗?

This is exercise, and source.c is the code that I have made myself, everything else was already given. 这是练习,source.c是我自己制作的代码,其他一切都已经给出了。 Idea was that I need to create dynamic array that contains Student structs in consecutive slots. 想法是我需要创建包含连续槽中的Student结构的动态数组。

As I understand, Valgrind thinks that in create_student malloc allocated too little memory for array entry and then test function (server side thing in our university) while compering my name string with its somehow points at NULL pointer and goes out memory bounds. 据我所知,Valgrind认为在create_student中malloc为数组输入分配了太少的内存然后测试函数(我们大学的服务器端的东西),同时用它的某种方式指向我的名字字符串指向NULL指针并输出内存边界。

I tried several approaches and this gives no errors or warnings by compiler (Code::Blocks) and works as intended but Valgrind still doesn't like it.. 我尝试了几种方法,这不会给编译器(Code :: Blocks)带来任何错误或警告,并按预期工作,但Valgrind仍然不喜欢它。

Thank you in the advance! 谢谢你提前!

Valgrind output: Valgrind输出:

==358== Invalid read of size 8
==358==    at 0x4016CB: test_create_student (test_source.c:38)
==358==    by 0x406340: srunner_run_all (in /tmc/test/test)
==358==    by 0x40288A: tmc_run_tests (tmc-check.c:121)
==358==    by 0x402544: main (test_source.c:310)
==358==  Address 0x518d768 is 0 bytes after a block of size 56 alloc'd
==358==    at 0x4C244E8: malloc (vg_replace_malloc.c:236)
==358==    by 0x402C5D: create_student (source.c:18)
==358==    by 0x401690: test_create_student (test_source.c:35)
==358==    by 0x406340: srunner_run_all (in /tmc/test/test)
==358==    by 0x40288A: tmc_run_tests (tmc-check.c:121)
==358==    by 0x402544: main (test_source.c:310)
==358== 
==358== Invalid read of size 1
==358==    at 0x4C25D94: strcmp (mc_replace_strmem.c:426)
==358==    by 0x4016DC: test_create_student (test_source.c:38)
==358==    by 0x406340: srunner_run_all (in /tmc/test/test)
==358==    by 0x40288A: tmc_run_tests (tmc-check.c:121)
==358==    by 0x402544: main (test_source.c:310)
==358==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==358== 
==358== 
==358== Process terminating with default action of signal 11 (SIGSEGV)
==358==  Access not within mapped region at address 0x0
==358==    at 0x4C25D94: strcmp (mc_replace_strmem.c:426)
==358==    by 0x4016DC: test_create_student (test_source.c:38)
==358==    by 0x406340: srunner_run_all (in /tmc/test/test)
==358==    by 0x40288A: tmc_run_tests (tmc-check.c:121)
==358==    by 0x402544: main (test_source.c:310)
==358==  If you believe this happened as a result of a stack
==358==  overflow in your program's main thread (unlikely but
==358==  possible), you can try to increase the size of the
==358==  main thread stack using the --main-stacksize= flag.
==358==  The main thread stack size used in this run was 8388608.

This is source file: 这是源文件:

#include "source.h"
#include "string.h"
#include "stdlib.h"

 /* Parameters:
 * s: pointer to the Students main structure (allocated by caller)
 * name: name of student
 * id: Student ID
 * age: age
 * course: course code
 * Returns: pointer to the student element in the array
 */
Student *create_student(Students *s, const char *name, const char *id,
        unsigned char age, const char *course)
{
    if(s->count == 0){
        s->array = malloc(sizeof(Student));
        if(s->array == NULL)
            return NULL;
    }
    if(s->count > 0){
        Student *nptr = realloc(s->array, (s->count+1)*sizeof(Student));
        if(nptr == NULL)
            return NULL;
        else
            s->array = nptr;
    }

    s->array[s->count].name = malloc((strlen(name)+1));                 /*Allocating memory for name pointer*/
    if(s->array[s->count].name == NULL)
        return NULL;
    memcpy(s->array[s->count].name, name, strlen(name));               /*Copying name string to the *name array*/
    s->array[s->count].name[strlen(name)] = '\0';

    if(strlen(id) > 8|| strlen(course) > 16)                            /*Checks if the strings are correct length*/
        return NULL;
    memcpy(s->array[s->count].id, id, strlen(id));                   /*Copying rest of the files*/
    s->array[s->count].id[strlen(id)] = '\0';
    memcpy(s->array[s->count].course, course, strlen(course));
    s->array[s->count].course[strlen(course)] = '\0';
    s->array[s->count].age = age;
    s->array[s->count].points = NULL;
    s->array[s->count].numPoints = 0;

    s->count++;                                                         /*Count is incremented by one as the first student is created*/
    s->array = &s->array[0];                                            /*Now *array points at the first entry in the array*/

    return &s->array[s->count];                                         /*Returns newly created pointer to the student*/
}


/* Parameters:
 * s: pointer to the Students main structure
 * id: Student ID to be looked for
 * course: Course code to be looked for
 * Returns: pointer to the student element in array, if found. NULL if not found
 */
Student *find_student(Students *s, const char *id, const char *course)
{
    Student *ptr = s->array;                                /*Creating pointer that points at the current student structure (starts from the beginning)*/
    int r1, r2;
    for(unsigned int i = 0; i < s->count; i++){
        r1 = strcmp(ptr->course, course);                   /*Checks for ID and course number*/
        r2 = strcmp(ptr->id, id);
        if(r1 == 0 && r2 == 0){
            return ptr;                                     /*Returns pointer to the student structure if matches*/
        }
        ptr++;
    }
    return NULL;                                            /*Returns NULL if no such student found*/
}

/* Parameters:
 * s: pointer to the Students main structure
 * id: Student ID to be deleted
 * course: Course from which student is deleted
 * Returns: 1 if deletion was successful, 0 if not (e.g. student not found)
 */
int delete_student(Students *s, const char *id, const char *course)
{
    Student *st0 = s->array;                                        /*Pointer at the first element in the array*/
    Student *stl = st0;                                             /*Pointer at the last element in the array*/
    for(int i = 0; i < (s->count-1); i++)
        stl++;
    if(find_student(s, id, course) == st0){                         /*1. Deleting the first element in the array*/
        s->count--;
        free(st0->name);
        for(int i = 0; i < s->count; i++)
            memcpy(st0+i, st0+(i+1), sizeof(Student));
        s->array = realloc(s->array, (s->count)*sizeof(Student));
        return 1;
    }
    else if(find_student(s, id, course) == stl){                    /*2. Deleting the last element in the array*/
        s->count--;
        free(stl->name);
        s->array = realloc(s->array, (s->count)*sizeof(Student));
        return 1;
    }
    else if(find_student(s, id, course) != NULL){                   /*3. Deleting the element in the middle of array*/
        int a = 0;
        while(st0 != find_student(s, id, course)){
            a++;
            st0++;
        }
        free(st0->name);
        s->count--;
        for(int i = 0; i < s->count-a; i++){
            memcpy(st0+i, st0+(i+1), sizeof(Student));
        }
        s->array = realloc(s->array, (s->count)*sizeof(Student));
        return 1;
    }
    return 0;
}


/* Parameters:
 * s: pointer to the Students main structure
 * id: student ID to set the points
 * course: course ID to set the points
 * points: array of points to be set to the student (will replace previous entry)
 * len: length of the points array
 * Returns: 1 if setting points was successful, 0 if not (e.g. student not found)
 */
int set_points(Students *s, const char *id, const char *course, const float *points, int len)
{
    Student *st = find_student(s, id, course);
    if(st != NULL){
        if(st->points == NULL){
            st->points = malloc(len * sizeof(int));
            for(int i = 0; i < len; i++)
                st->points[i] = points[i];
            st->numPoints = len;
            return 1;
        }
        else{
            st->points = realloc(st->points, len * sizeof(int));
            for(int i = 0; i < len; i++)
                st->points[i] = points[i];
            st->numPoints = len;
            return 1;
        }
    }
    return 0;
}

And this is source.h: 这是source.h:

typedef struct student Student;

struct student {
    char *name; // name of the student
    char id[8]; // null-terminated student ID
    unsigned char age;
    char course[16]; // null-terminated course code;
    float *points; // pointer to dynamic array of exercise points
    unsigned int numPoints; // length of the above array
};

typedef struct {
    unsigned int count; // size of the students array
    Student *array; // pointer to the first element in the array
} Students;

Student *create_student(Students *s, const char *name, const char *id,
        unsigned char age, const char *course);
Student *find_student(Students *s, const char *id, const char *course);
int delete_student(Students *s, const char *id, const char *course);
int set_points(Students *s, const char *id, const char *course, const float *points, int len);

And this is main: 这是主要的:

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "source.h"

void print_students(Students *s)
{
    Student *st = s->array;
    for (unsigned int i = 0; i < s->count; i++) {
        printf("%s (%s), Course: %s, Age: %d\n", st->name, st->id, st->course, st->age);
        if (st->numPoints) {
            printf(" -- Points: ");
            for (unsigned int j = 0; j < st->numPoints; j++)
                printf("%f  ", st->points[j]);
            printf("\n");
        }
        st++;
    }
}

void initialize_reg(Students *reg) {
    assert(reg != NULL);
    reg->count = 0;
    reg->array = NULL;
    create_student(reg, "Teemu Teekkari", "00000A", 20, "ELEC-A1100");
    create_student(reg, "Matti Meikäläinen", "12345B", 28, "ELEC-A1100");
    create_student(reg, "Wow", "33333C", 28, "ELEC-A1100");
    create_student(reg, "Much Student", "98765H", 28, "ELEC-A1100");
    create_student(reg, "Such course", "12121R", 28, "ELEC-A1111");
    create_student(reg, "Amaze", "11111T", 28, "ELEC-A1111");
}

int main()
{
    Students s;
    s.count = 0;
    s.array = NULL;

    // create a group of students using create_student
    initialize_reg(&s);
    print_students(&s);

    // Try find_student 
    Student *sf3 = find_student(&s, "33333C", "ELEC-A1100");
    Student *sf6 = find_student(&s, "11111T", "ELEC-A1111");
    if (!sf3) {
        printf("Did not find existing student 33333C\n");
    } else if (strcmp(sf3->id, "33333C")) {
        printf("Incorrect student ID %s when should have been 33333C\n", sf3->id);
    }
    if (!sf6) {
        printf("Did not find existing student 11111T\n");
    } else if (strcmp(sf6->id, "11111T")) {
        printf("Incorrect student ID %s when should have been 11111T\n", sf6->id);
    }

    // Try delete_student with existing student
    if (!delete_student(&s, "12121R", "ELEC-A1111")) {
        printf("Delete student failed for existing student\n");
    }

    printf("-----\n");
    float p[] = {3.0, 1.0, 4.0, 4.5};
    set_points(&s, "00000A", "ELEC-A1100", p, 4);
    print_students(&s);
    printf("-----\n");

    // Try delete_student with non_existing student
    delete_student(&s, "33333C", "ELEC-A1100");
    print_students(&s);
}

This is test_source to which Valgrind refers to: 这是Valgrind引用的test_source:

#include <check.h>
#include "tmc-check.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include "../src/source.h"

void release_memory(Students *s) {
    unsigned int i;
    if (s->array) {
        for (i = 0; i < s->count; i++) {
            Student *st = &(s->array[i]);
            if (st->name)
                free(st->name);
            if (st->points)
                free(st->points);
        }
        free(s->array);
    }
}

START_TEST(test_create_student) {
    Students reg;
    //assert(reg != NULL);
    reg.count = 0;
    reg.array = NULL;
    char buf[160];

    //char *name = malloc(strlen("Teemu Teekkari") + 1);
    //strcpy(name, "Teemu Teekkari");
    char *name = "Teemu Teekkari";

    Student *s1 = create_student(&reg, name, "00000A", 20, "ELEC-A1100");
    fail_unless(s1 != NULL, "[Task 3.4.a] create_student returned NULL.\n");

    if (strcmp(name, s1->name)) {
        sprintf(buf, "[Task 3.4.a] Student name should be %s, was %s.\n", name, s1->name);
        release_memory(&reg);
        fail(buf);
    }

    if (strcmp("00000A", s1->id)) {
        sprintf(buf, "[Task 3.4.a] Student ID should be %s, was %s.\n", "00000A", s1->id);
        release_memory(&reg);
        fail(buf);
    }

    if (s1->age != 20) {
        sprintf(buf, "[Task 3.4.a] Student age should be 20, was %d\n.", s1->age);
        release_memory(&reg);
        fail(buf);
    }

    if (strcmp("ELEC-A1100", s1->course)) {
        sprintf(buf, "[Task 3.4.a] Course code not should be %s, was %s.\n", "ELEC-A1100", s1->course);
        release_memory(&reg);
        fail(buf);
    }

    if (s1->points != NULL) {
        sprintf(buf, "[Task 3.4.a] Points array should be NULL, was %p.\n", s1->points);
        release_memory(&reg);
        fail(buf);
    }

    if (s1->numPoints != 0) {
        sprintf(buf, "[Task 3.4.a] numPoints should be 0, was %d.\n", s1->numPoints);
        release_memory(&reg);
        fail(buf);
    }

    //free(name);
    //fail_unless(!strcmp("Teemu Teekkari", s1->name), "[Task 17.1] Student name was not allocated from heap.");

    if (reg.count != 1) {
        sprintf(buf, "[Task 3.4.a] After adding a student, student count should be 1, was %d.\n",
                reg.count);
        release_memory(&reg);
        fail(buf);
    }

    if (reg.array != s1) {
        release_memory(&reg);
        fail("[Task 3.4.a] After adding one student, the returned value does not point to the beginning of array.\n");
    }

    Student *s2 = create_student(&reg, "Peppilotta Sikuriina Rullakartiina Kissanminttu Efraimintytar Pitkatossu", "12345B", 10, "ELEC-A1100");
    if ((reg.array) + 1 != s2) {
        release_memory(&reg);
        fail("[Task 3.4.a] After adding second student, the returned value does not point to the second array member.\n");
    }

    if (reg.count != 2) {
        sprintf(buf, "[Task 3.4.a] After adding second student, the student count should be 2, was %d.\n",
                reg.count);
        release_memory(&reg);
        fail(buf);
    }

#if 0
    Student *s3 = create_student(&reg, "Ylimaaraisia Merkkeja", "99999Ffoofoofoofoo", 60, "ELEC-A1111-even-16-characters-is-too-much-for-a-course-code");
    assert(s3 != NULL);

    if (strcmp("99999Ff", s3->id)) {
        sprintf("[Task 3.4.a] Too long student id truncated incorrectly: %s, should be %s\n",
                s3->id, "99999Ff");
        release_memory(&reg);
        fail(buf);
    }
    if (strcmp("ELEC-A1111-even", s3->course)) {
        sprintf(buf, "[Task 3.4.a] Too long course code truncated incorrectly: %s, should be %s\n",
                s3->course, "ELEC-A1111-even");
        release_memory(&reg);
        fail(buf);
    }
#endif
    release_memory(&reg);
}

END_TEST

Students *initialize_reg(Students *reg) {
    //Students *reg = malloc(sizeof(Students));
    assert(reg != NULL);
    reg->count = 0;
    reg->array = NULL;
    create_student(reg, "Teemu Teekkari", "00000A", 20, "ELEC-A1100");
    create_student(reg, "Matti Meikäläinen", "12345B", 28, "ELEC-A1100");
    create_student(reg, "Wow", "33333C", 28, "ELEC-A1100");
    create_student(reg, "Much Student", "98765H", 28, "ELEC-A1100");
    create_student(reg, "Such course", "12121R", 28, "ELEC-A1111");
    create_student(reg, "Amaze", "11111T", 28, "ELEC-A1111");
    return reg;
}

START_TEST(test_find_student) {
    Students regb;
    char buf[160];
    Students *reg = initialize_reg(&regb);
    Student *sf3 = find_student(reg, "33333C", "ELEC-A1100");
    Student *sf6 = find_student(reg, "11111T", "ELEC-A1111");

    if (sf3 == NULL) {
        release_memory(reg);
        fail("[Task 3.4.b] find_student returned NULL for existing student ID %s.\n", "33333C");
    }

    if (strcmp(sf3->id, "33333C")) {
        sprintf(buf, "[Task 3.4.b] find_student returned student with wrong id. Searched for: %s, returned: %s", "33333C", sf3->id);
        release_memory(reg);
        fail(buf);
    }

    if (sf6 == NULL) {
        release_memory(reg);
        fail("[Task 3.4.b] find_student returned NULL for existing student %s.\n", "11111T");
    }

    if (strcmp(sf6->id, "11111T")) {
        sprintf(buf, "[Task 3.4.b] find_student returned student with wrong id. Searched for: %s, returned: %s", "11111T", sf6->id);
        release_memory(reg);
        fail(buf);
    }

    if (NULL != find_student(reg, "98989D", "ELEC-A1112")) {
        release_memory(reg);
        fail("[Task 3.4.b] find_student should return NULL for nonexistent students.\n");
    }

    /*    fail_unless(NULL == find_student(reg, "98989D", "ELEC-A1100"), "[Task 17.2] find_student should return NULL for nonexistent students.");
        fail_unless(NULL == find_student(reg, "33333C", "ELEC-A1112"), "[Task 17.2] find_student should return NULL for nonexistent students.");
        fail_unless(NULL == find_student(reg, "33333C", "ELEC-A1111"), "[Task 17.2] find_student should return NULL for nonexistent students.");*/
    release_memory(reg);
}

END_TEST


START_TEST(test_delete_student) {
    char buf[160];
    Students regb;
    Students *reg = initialize_reg(&regb);
    if (reg->count != 6) {
        sprintf(buf, "[Task 3.4.c] Wrong student count after adding 6 students, you have %d\n.",
                reg->count);
        release_memory(reg);
        fail(buf);
    }

    if (!delete_student(reg, "11111T", "ELEC-A1111")) {
        sprintf(buf, "[Task 3.4.c] delete_student() failed for existing student 11111T.\n");
        release_memory(reg);
        fail(buf);
    }

    if (reg->count != 5) {
        sprintf(buf, "[Task 3.4.c] After deleting one student, student count should be 5, you had %d.\n",
                reg->count);
        release_memory(reg);
        fail(buf);
    }

    if (!delete_student(reg, "33333C", "ELEC-A1100")) {
        sprintf(buf, "[Task 3.4.c] delete_student() failed for existing student 33333C.\n");
        release_memory(reg);
        fail(buf);
    }
    //fail_unless(reg->count == 4, "[Task 17.3] Wrong student count after deletion.");

    assert((reg->array + 2) != NULL);

    if (strcmp((reg->array + 2)->id, "98765H")) {
        sprintf(buf, "[Task 3.4.c] After deleting student 33333C, student %s should be in 3rd array position. You have %s.\n", "98765H", (reg->array + 2)->id);
        release_memory(reg);
        fail(buf);
    }

    if (delete_student(reg, "33330C", "ELEC-A1101")) {
        release_memory(reg);
        fail("[Task 3.4.c] delete_student() should have failed for nonexisting student 33330C.\n");
    }
    /*fail_unless(delete_student(reg, "00000A", "ELEC-A1111") == 0, "[Task 17.3] delete_student() should have failed for nonexisting student.");
    fail_unless(delete_student(reg, "12121R", "ELEC-A1100") == 0, "[Task 17.3] delete_student() should have failed for nonexisting student.");
    fail_unless(delete_student(reg, "00000A", "ELEC-A1100"), "[Task 17.3] delete_student() failed for existing student 00000A.");
    fail_unless(delete_student(reg, "12345B", "ELEC-A1100"), "[Task 17.3] delete_student() failed for existing student 12345B.");
    fail_unless(delete_student(reg, "98765H", "ELEC-A1100"), "[Task 17.3] delete_student() failed for existing student 98765H.");
    fail_unless(delete_student(reg, "12121R", "ELEC-A1111"), "[Task 17.3] delete_student() failed for existing student 12121R.");

    fail_unless(reg->count == 0, "[Task 17.3] Course register should be empty after deleting all students.");*/

    release_memory(reg);
}

END_TEST


void pr_array(char *buf, float *arr, int n) {
    char b[40];
    sprintf(buf, "{");
    while (n--) {
        sprintf(b, "%.1f", *arr++);
        if (n)
            strcat(b, ", ");
        strcat(buf, b);
    }
    strcat(buf, "}");
}

START_TEST(test_set_points) {
    Students regb;
    Students *reg = initialize_reg(&regb);
    char arrbuf[80];
    char buf[160];
    float p[4];
    int i;
    for (i = 0; i < 4; i++) {
        p[i] = (float)(rand() % 10) / 2;
    }
    pr_array(arrbuf, p, 4);

    if (!set_points(reg, "00000A", "ELEC-A1100", p, 4)) {
        sprintf(buf, "[Task 3.4.d] set_points() returned 0 for student 00000A with array %s, but it should have succeeded.\n",
                arrbuf);
        release_memory(reg);
        fail(buf);
    }
    Student *st = &(reg->array[0]);

    if (st->points == NULL) {
        sprintf(buf, "[Task 3.4.d] Points array not created for array %s (is still NULL).\n",
                arrbuf);
        release_memory(reg);
        fail(buf);
    }

    char arr2[80];
    pr_array(arr2, st->points, 4);
    for (i = 0; i < 4; i++) {
        if (st->points[i] != p[i]) {
            sprintf(buf, "[Task 3.4.d] Point array differs. Should be %s. You have %s\n",
                    arrbuf, arr2);
            release_memory(reg);
            fail(buf);
        }
    }
    /*float q[] = {2, 5, 1, 6, 12, 1};
    fail_unless(set_points(reg, "00000A", "ELEC-A1100", q, 6) == 1, "[Task 17.4] set_points() did not return 1 on success or failed when it was not supposed to");
    fail_unless(st->points != NULL, "[Task 17.4] Points array for student not created");
    fail_unless(st->points[4] == 12, "[Task 17.4] Setting points failed on student");
    fail_unless(set_points(reg, "00000A", "ELEC-A1111", p, 3) == 0, "[Task 17.4] set_points() did not return 0 on failure");*/

    release_memory(reg);
}

END_TEST


int main(int argc, const char *argv[]) {
    srand((unsigned) time(NULL));
    Suite *s = suite_create("Test-3.4");

    /* TODO: define tests */
    tmc_register_test(s, test_create_student, "3.4.a");
    tmc_register_test(s, test_find_student, "3.4.b");
    tmc_register_test(s, test_delete_student, "3.4.c");
    tmc_register_test(s, test_set_points, "3.4.d");

    return tmc_run_tests(argc, argv, s);
}

And with the test source code, combined with my last comment, it's now easy to see the problem: 使用测试源代码,结合我的上一条评论,现在很容易看到问题所在:

You return a Student pointer that points beyond the allocated memory. 返回指向超出分配内存的Student指针。

By the point the create_student function returns, you have increased s->count so it's the number of entries in the "array" s->array . create_student函数返回时,您增加了s->count因此它是“array” s->array的条目数。 But size array-indices are zero-base, the max index is s->count - 1 at that point. 但是大小数组索引是零基数,最大索引是s->count - 1

The create_student() function ends with: create_student()函数以以下结尾:

s->count++;   /*Count is incremented by one as the first student is created*/
s->array = &s->array[0];   /*Now *array points at the first entry in the array*/
return &s->array[s->count];   /*Returns newly created pointer to the student*/

I'm epically sceptic towards this code. 我对这段代码非常怀疑。

The first line is fine; 第一行很好; there's one more student stored now than there was before the function ran. 现在存储的学生比函数运行之前还多了一个。 The comment is broken though. 评论虽然破了。

The second line is broken, it re-assigns array , a newly allocated dynamic pointer. 第二行被破坏,它重新分配array ,一个新分配的动态指针。 You should never do that. 你永远不应该这样做。 Fortunately it's a no-op, setting it to itself. 幸运的是,这是一个无操作,将其设置为自己。 The comment implies that you think it does something though, which makes it scary. 评论意味着你认为它做了一些事情,这让它变得可怕。

The third line is super-scary; 第三行是超级可怕的; it returns a pointer to once past the array , remember that count has been incremented. 它返回一个指向一次超过数组的指针,记住count已递增。

If called with count == 0 , the function malloc() s space for a single Student , then returns a pointer to the second element in an array of one. 如果使用count == 0调用,则函数malloc()为单个Student的空间,然后返回指向数组中第二个元素的指针。 Bad! 坏!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM