malloc dynamic array in dynamic array of structs

前端 未结 3 1018
情书的邮戳
情书的邮戳 2021-01-26 00:30
typedef struct {
    char *word;
} STR;

int main()
{
    STR *arr=(STR*)malloc(5*sizeof(*arr));
    STR[2].word=(char*)malloc(200*sizeof(char));
    STR[2].word=(char*)         


        
相关标签:
3条回答
  • 2021-01-26 00:59
    #include <stdio.h>
    #include <stdlib.h>
    
    
    typedef struct{
        char *word;
    }STR;
    
    int main(){
        STR *arr=(STR*)malloc(5*sizeof(STR));
        arr[2].word=(char*)malloc(200*sizeof(char));
        if(realloc(arr[2].word, 400*sizeof(char))==NULL){
            /* increasing char array size from 200 to 400 failed. 200 char array was unchanged */
            printf("increasing array size not OK\n");
        }
        else{
            printf("increasing array size OK\n");
        }
        free(arr[2].word);
        free(arr);
        return 0;
    }
    
    0 讨论(0)
  • 2021-01-26 01:14

    This seems redundant. But, if you are trying to create an array of strings using your structure, where the third element is malloc'd as a 199 character string and then realloced as a 399 character string, you would do it like so:

    STR *arr = (STR*)malloc(5*sizeof(STR));
    arr[2].word = (char*)malloc(200*sizeof(char));
    arr[2].word = (char*)realloc(arr[2].word,400*sizeof(char));
    
    0 讨论(0)
  • 2021-01-26 01:15

    Your primary problem is you are using the typedef name STR where you should be using the variable name arr when allocating and reallocating arr[2].word.

    Do NOT cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc? for thorough explanation. All you need to allocate an array of 5 STR is:

    STR *arr = malloc (5 * sizeof (*arr));  /* allocate array of 5 STR */
    

    (note: the parenthesis are optional with sizeof, so it could also be properly written):

    STR *arr = malloc (5 * sizeof *arr);    /* allocate array of 5 STR */
    

    After you declare STR *arr = malloc (5 * sizeof (*arr)), you allocate word as follows:

    arr[2].word = malloc (200 * sizeof *(arr[2].word));
    

    NOT

    STR[2].word = malloc (200 * sizeof *(arr[2].word));
    

    You must validate every allocation. E.g.:

    STR *arr = malloc (5 * sizeof (*arr));  /* allocate array of 5 STR */
    
    if (!arr) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;  /* or handle error as appropriate */
    }
    

    Never realloc using the pointer itself, if realloc fails, you have lost the pointer to your original data and cannot free the memory. Instead use a simple temporary variable:

    void *tmp = realloc (arr[2].word, 400 * sizeof *(arr[2].word));
    if (!tmp) {
        fprintf (stderr, "error: realloc() virtual memory exhausted.\n");
        return 1;
    }
    arr[2].word = tmp;
    

    In any code your write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. Get in the habit of tracking and freeing all memory you allocate rather than relying on it being done by exit. This will pay dividends when you begin writing more complex code that allocates memory within functions in your code. In this case, you would need:

    free (arr[2].word); /* free allocated memory */
    free (arr);
    

    Putting those pieces together, you could do:

    typedef struct {
        char *word;
    } STR;
    
    int main (void)
    {
        STR *arr = malloc (5 * sizeof (*arr));  /* allocate array of 5 STR */
    
        if (!arr) { /* validate allocation */
            fprintf (stderr, "error: virtual memory exhausted.\n");
            return 1;  /* or handle error as appropriate */
        }
    
        /* allocate/validate arr[2].word */
        if (!(arr[2].word = malloc (200 * sizeof *(arr[2].word)))) {
            fprintf (stderr, "error: virtual memory exhausted.\n");
            return 1;  /* or handle error as appropriate */
        }
    
        /* realloc/validate using temporary variable */
        void *tmp = realloc (arr[2].word, 400 * sizeof *(arr[2].word));
        if (!tmp) {
            fprintf (stderr, "error: realloc() virtual memory exhausted.\n");
            return 1;
        }
        arr[2].word = tmp;
    
        free (arr[2].word); /* free allocated memory */
        free (arr);
    
        return 0;
    }
    

    Example Use/Valgrind Output

    It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an uninitialized value and finally to confirm that you have freed all the memory you have allocated.

    For Linux valgrind is the normal choice. There are many subtle ways to misuse a pointer or new block of memory. Using a memory error checker allows you to identify any problems and validate proper use of of the memory you allocate rather than finding a problem exists through a segfault. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.

    For example, compiling your code and saving the executable as ./bin/alloc, you would then make basic use of valgrind simply by running valgrind with your program as the first argument:

    $ valgrind ./bin/alloc
    ==8949== Memcheck, a memory error detector
    ==8949== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
    ==8949== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
    ==8949== Command: ./bin/alloc
    ==8949==
    ==8949==
    ==8949== HEAP SUMMARY:
    ==8949==     in use at exit: 0 bytes in 0 blocks
    ==8949==   total heap usage: 3 allocs, 3 frees, 640 bytes allocated
    ==8949==
    ==8949== All heap blocks were freed -- no leaks are possible
    ==8949==
    ==8949== For counts of detected and suppressed errors, rerun with: -v
    ==8949== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
    

    Always confirm All heap blocks were freed -- no leaks are possible and equally important ERROR SUMMARY: 0 errors from 0 contexts. (note: some OS's do not provide adequate memory exclusion files (the file that excludes system and OS memory from being reported as in use) which will cause valgrind to report that some memory has not yet been freed despite the fact you have done your job and freed all blocks you allocated and under your control.)

    Look it over and let me know if you have any questions.

    (note: C favors lower-case names, reserving all-caps for constants and macros. It's just style, so it is up to you.)

    0 讨论(0)
提交回复
热议问题