简体   繁体   中英

C programming creating a dynamic array

Up to now you have created static arrays, a fixed size. Dynamic arrays can use structs and malloc() to change their size. When the array is full: Allocate a new block of memory. Copy the data from one pointer to the other. Free the old pointer. Assign the new pointer to the dynamic array struct

You only have to implement the functions to initialize the dynamic array and to expand the dynamic array. Follow the comments to see what you need to code. The comments that need code have TODO: written in them memcpy(void *dest, void *src, int bytes) A useful function for copying memory between pointers. Parameter 1: destination pointer you are copying to. Parameter 2: source pointer you are copying from. Parameter 3: number of bytes to copy

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

//The dynamic array struct.  This maintains my pointer to memory, effective size and maximum size
typedef struct
{
    double *arrayPointer;
    int effectiveSize;
    int maximumSize;
} DynamicArray;

//Initialize the dynamic array
void CreateArray(DynamicArray *mArray, int initialSize)
{
    //TODO: Use malloc to create an array of the initial size.  Assign to the arrayPointer variable

    //TODO: Set effective size to 0 and maximum size to the initial size
}

//Expand the array to a new size
void ExpandArray(DynamicArray *mArray, int newSize)
{
    //TODO: Create a new pointer (double *newArray) and set it with a malloc call of the new size

    //TODO: Using either memcpy or a for loop, copy all of the data from the old array to the new one.
    //You are only copying to mArray->maximumSize, not the new size.

    //TODO: Using the free function, release the previous mArray->arrayPointer

    //TODO: Update mArray with the new pointer and the new maximum size.  Effective size does not change.
}

//Add a new value from the user to the array
void AddValue(DynamicArray *mArray)
{
    //Get the input
    double input;
    printf("Enter a new value: ");
    scanf_s("%lf", &input);

    //Assign the input to the array.  Increase effective size
    mArray->arrayPointer[mArray->effectiveSize] = input;
    mArray->effectiveSize++;

    //If effective size is now the same as maximum size we need to expand.
    if (mArray->effectiveSize == mArray->maximumSize)
    {
        //Output that we are expanding
        printf("Expanding array from %d to %d\n", mArray->maximumSize, mArray->maximumSize * 2);

        //Double the size of the array
        ExpandArray(mArray, mArray->maximumSize * 2);
    }
}

//Print the array
void PrintArray(const DynamicArray *mArray)
{
    int i;

    //Walk through the array up to effective size and print the values
    for (i = 0; i < mArray->effectiveSize; i++)
    {
        printf("%.2lf ", mArray->arrayPointer[i]);
    }
    printf("\n");
}

int main(void)
{
    int i;

    //Create my dynamic array of size 5
    DynamicArray mArray;
    CreateArray(&mArray, 5);

    //Add five values to it
    for (i = 0; i < 5; i++)
    {
        AddValue(&mArray);
    }

    //Print the array
    PrintArray(&mArray);

    //Add five more values
    for (i = 0; i < 5; i++)
    {
        AddValue(&mArray);
    }

    //Print the array
    PrintArray(&mArray);
    system("pause");
}

the picture is how its suppose to look like.

Please help as i am stuck and dont know what to do

If you are going to dynamically allocate storage for anything, you first need a pointer to type. You declared 1 static variable of type DynamicArray with DynamicArray mArray; . Instead you need DynamicArray *mArray; and you may as well initialize it to NULL :

int main (void) {

    /* Create my dynamic array of size 5 */
    DynamicArray *mArray = NULL;
    CreateArray (&mArray, 5);

    return 0;
}

Since you have a pointer, when you send the address to CreateArray , the funciton parameter must be a double-pointer . Then in CreateArray , to allocate for mArray , you must dereference the value passed as an argument and allocate *mArray = malloc... . You can also use calloc in place of malloc which for a negligible amount of additional overhead will allocate and initialize the new block of memory to zero:

/* Initialize the dynamic array */
void CreateArray (DynamicArray **mArray, int initialSize)
{
    /*  TODO: Use malloc to create an array of the initial size.
        Assign to the arrayPointer variable */

    /* using calloc will allocate & initialize to zero */
    *mArray = calloc (initialSize, sizeof **mArray);

    if (!(*mArray)) {
        fprintf (stderr, "CreateArray() error: virtual memory exhausted.\n");
        exit (EXIT_FAILURE);
    }

}

Unless you have some requirement to use a void type for the funciton, why not return the pointer as well?

DynamicArray *CreateArray (DynamicArray **mArray, int initialSize)
{
    /*  TODO: Use malloc to create an array of the initial size.
        Assign to the arrayPointer variable */

    /* using calloc will allocate & initialize to zero */
    *mArray = calloc (initialSize, sizeof **mArray);

    if (!(*mArray)) {
        fprintf (stderr, "CreateArray() error: virtual memory exhausted.\n");
        exit (EXIT_FAILURE);
        /* or you can now: 'return NULL;' instead of exiting. */
    }

    return *mArray;
}

Lastly, in any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed . It is also imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory and to confirm that you have freed all the memory you have allocated. For Linux valgrind is the normal choice. There are so many subtle ways to misuse a block of memory that can cause real problems, there is no excuse not to do it.

Additional Example

So, you need a bit more help sewing it all together. Here is a short example that allocates a dynamic array of 5 struct DynamicArray and initializes the elements 0 and 4 . It then prints the values in the double array pointed to by arrayPointer for the 4th element and then frees the memory allocated. I have also included the compile string and the valgrind memory error check:

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

#define DASIZE 5

typedef struct {
    double *arrayPointer;
    int effectiveSize;
    int maximumSize;
} DynamicArray;

void CreateArray (DynamicArray **mArray, int initialSize);

int main (void) {

    double tmp[] = {0.0, 0.1, 0.2, 0.3};
    int i;

    /* Create my dynamic array of size 5 */
    DynamicArray *mArray = NULL;
    CreateArray (&mArray, DASIZE);

    /* assign pointer and values for element 0 */
    mArray[0].arrayPointer = tmp;
    mArray[0].effectiveSize = sizeof tmp/sizeof *tmp;
    mArray[0].maximumSize = mArray[0].effectiveSize;

    /* assign pointer and values for element 4 */
    mArray[4].arrayPointer = tmp;
    mArray[4].effectiveSize = sizeof tmp/sizeof *tmp;
    mArray[4].maximumSize = mArray[4].effectiveSize;

    /* print values for element 4 */
    printf ("\n information for mArray[4]:\n\n");
    printf ("   mArray[4].effectiveSize : %d\n", mArray[4].effectiveSize);
    printf ("   mArray[4].maximumSize   : %d\n\n", mArray[4].maximumSize);
    for (i = 0; i < mArray[4].effectiveSize; i++)
        printf ("   mArray[4].arrayPointer[%d] : %.1lf\n",
                i, mArray[4].arrayPointer[i]);

    free (mArray);  /* free all memory allocated */

    putchar ('\n'); /* add an additional newline to make it look nice */

    return 0;
}

/* Allocate memory for dynamic array of struct */
void CreateArray (DynamicArray **mArray, int initialSize)
{
    /* using calloc will allocate & initialize to zero */
    *mArray = calloc (initialSize, sizeof **mArray);

    if (!(*mArray)) {
        fprintf (stderr, "CreateArray() error: virtual memory exhausted.\n");
        exit (EXIT_FAILURE);
    }
}

Compile

gcc -Wall -Wextra -O2 -o bin/array_dyn_min array_dyn_min.c

Use/Output

$ ./bin/array_dyn_min

 information for mArray[4]:

   mArray[4].effectiveSize : 4
   mArray[4].maximumSize   : 4

   mArray[4].arrayPointer[0] : 0.0
   mArray[4].arrayPointer[1] : 0.1
   mArray[4].arrayPointer[2] : 0.2
   mArray[4].arrayPointer[3] : 0.3

Memory/Error Check

$ valgrind ./bin/array_dyn_min
==2232== Memcheck, a memory error detector
==2232== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==2232== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==2232== Command: ./bin/array_dyn_min
==2232==

 information for mArray[4]:

   mArray[4].effectiveSize : 4
   mArray[4].maximumSize   : 4

   mArray[4].arrayPointer[0] : 0.0
   mArray[4].arrayPointer[1] : 0.1
   mArray[4].arrayPointer[2] : 0.2
   mArray[4].arrayPointer[3] : 0.3

==2232==
==2232== HEAP SUMMARY:
==2232==     in use at exit: 0 bytes in 0 blocks
==2232==   total heap usage: 1 allocs, 1 frees, 80 bytes allocated
==2232==
==2232== All heap blocks were freed -- no leaks are possible
==2232==
==2232== For counts of detected and suppressed errors, rerun with: -v
==2232== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

The important lines for the memory error check are:

  total heap usage: 1 allocs, 1 frees, 80 bytes allocated
...
All heap blocks were freed -- no leaks are possible
...
ERROR SUMMARY: 0 errors from 0 contexts...

Which tells you there was '1' dynamic memory allocation and '1' free, and that all memory allocated was freed, and there were no memory errors with the use of the memory during the program. You can ignore the (suppressed: 2 from 2) which is valgrind telling you that it is missing the symbol tables (debug versions) of 2 libraries. (on my system, because they are not installed...)

Here is what i had tocome up with thank you

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

typedef struct
{
    double *arrayPointer;
    int effectiveSize;
    int maximumSize;
} DynamicArray;

void CreateArray(DynamicArray *mArray, int initialSize)
{
    mArray->arrayPointer = (double *)malloc(sizeof(double) * initialSize);
    mArray->effectiveSize = 0;
    mArray->maximumSize = initialSize;
}

void ExpandArray(DynamicArray *mArray, int newSize)
{
    double *newArray = (double *)malloc(sizeof(double) * newSize);
    memcpy(newArray, mArray->arrayPointer, sizeof(double) * mArray->maximumSize);
    free(mArray->arrayPointer);
    mArray->arrayPointer = newArray;
    mArray->maximumSize = newSize;
}

void AddValue(DynamicArray *mArray)
{
    double input;
    printf("Enter a new value: ");
    scanf_s("%lf", &input);

    mArray->arrayPointer[mArray->effectiveSize] = input;
    mArray->effectiveSize++;

    if (mArray->effectiveSize == mArray->maximumSize)
    {
        printf("Expanding array from %d to %d\n", mArray->maximumSize, mArray->maximumSize * 2);
        ExpandArray(mArray, mArray->maximumSize * 2);
    }
}

void PrintArray(const DynamicArray *mArray)
{
    int i;
    for (i = 0; i < mArray->effectiveSize; i++)
    {
        printf("%.2lf ", mArray->arrayPointer[i]);
    }
    printf("\n");
}

int main(void)
{
    int i;
    DynamicArray mArray;
    CreateArray(&mArray, 5);
    for (i = 0; i < 5; i++)
    {
        AddValue(&mArray);
    }
    PrintArray(&mArray);
    for (i = 0; i < 5; i++)
    {
        AddValue(&mArray);
    }
    PrintArray(&mArray);
    system("pause");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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