Thread: Need help transferring contents of one character array to another in function

  1. #1
    Registered User
    Join Date
    Oct 2013
    Posts
    29

    Need help transferring contents of one character array to another in function

    In the function *expandArrayList and *trimArrayList I need to allocate either more memory or less memory to the given array. Right now I am using malloc on a new array and then transferring the elements of the original array to the new array, freeing the original array, and then reassigning it to the new array so it's size and capacity are either bigger or smaller than the original. I feel like there has to be a simpler way to do this with either realloc or calloc, but I cant find sufficient information on either online. Would I be able to use either to make this easier and the code cleaner?

    Also, these are character arrays that contain several character arrays inside them, so I was wondering what the best way to transfer the contents of one array to the other would be. I have gone between

    Code:
    //example
    for (i=0; i<length; i++){
         newarray[i] = oldarray[i];
    }
    and
    Code:
    for (i=0; i<length; i++){
         strcpy(newarray[i], oldarray[i]);
    }
    but I'm not sure which one (if either) should work.



    The 'ArrayList.h' file that is included contains the structure ArrayList, as well as the function prototypes for the functions listed below.

    Here is the structure in ArrayList.h:
    Code:
    #define DEFAULT_INIT_LEN 10
    
    typedef struct ArrayList
    {
     // We will store an array of strings (i.e., an array of char arrays)
     char **array;
     // Size of list (i.e., number of elements that have been added to the array)
     int size;
     // Length of the array (i.e., the array's current maximum capacity)
     int capacity;
    } ArrayList;
    Here is my code:

    Code:
    //included libraries
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "ArrayList.h"
    //Create arraylist
    ArrayList *createArrayList(int length){
    //Dynamically allocate space for new ArrayList
    ArrayList *L = malloc(sizeof(ArrayList));
    int i;
    //initialize to NULL
    L->array = NULL;
    //set the size of the arraylist to whichever one is bigger
    if (length >= DEFAULT_INIT_LEN)
    {
    //create arraylist of size length
    L->array = malloc(sizeof(char*)*length);
    if (L->array != NULL)
    {
    printf("-> Created new ArrayList of size %d\n",length);
    //initialize pointers in array to NULL
    for (i=0; i<length; i++){
        L->array[i] = NULL;
    }
    //Set size and capacity
    L->size = 0;
    L->capacity = length;
    return L;
    }
    //In case malloc fails
    else{
    printf("\n malloc failed.\n");
    return NULL;}
    }
    //if length is smaller than default size
    else
    {
    //set arraylist to size DEFAULT_INIT_LEN
    L->array = malloc(sizeof(char*)*DEFAULT_INIT_LEN);
    if (L->array != NULL)
    {
    printf("-> Created new ArrayList of size %d\n",DEFAULT_INIT_LEN);
    //initialize pointers in array to NULL
    for (i=0; i<DEFAULT_INIT_LEN; i++){
        L->array[i] = NULL;
    }
    //set size and capacity
    L->size = 0;
    L->capacity = DEFAULT_INIT_LEN;
    return L;
    }
    //in case malloc failed
    else{
    printf("\nmalloc failed.\n");
    return NULL;
    }}}
    //Destroy arraylist
    ArrayList *destroyArrayList(ArrayList *list){
    int i;
    //free everything in the array first, then free the array itself
    for (i=0; i<list->capacity; i++){
        free(list->array[i]);
    }
    free(list->array);
    list->size = 0;
    list->capacity = 0;
    free(list);
    //set list to NULL and return list
    list = NULL;
    return list;
    }
    //Expand arraylist to new size
    ArrayList *expandArrayList(ArrayList *list, int length){
    int i;
    char **newarray = NULL;
    //find how many elements are currently in the array
    int arrsize = sizeof(list->array)/sizeof(list->array[0]);
    //create a new (larger) array to store the contents of the old array
    newarray = malloc(sizeof(char*)*length);
    //dont do anything if the length is smaller than the current capcity
    //or if the list was NULL
    if (length <= list->capacity)
        return NULL;
    if (list == NULL)
        return NULL;
    //make sure malloc was successful
    if (newarray != NULL){
    //copy the contents of list->array into newarray
    for (i=0; i<length; i++){
    strcpy(newarray[i], list->array[i]);}
    
    //free the orginal array, since it has been copied over to the new array
    for(i=0; i<list->capacity; i++){
            free(list->array[i]);
            }
    free(list->array);
    //set list->array to point to the newly created array
    list->array = &newarray;
    //let user know the function was successful
    printf("-> Expanded ArrayList to size %d", length);
    //set new size and capacity if they were changed
    list->size = arrsize;
    list->capacity = length;
    //return the pointer to 
    return list;
    }
    //if malloc was unsuccessful
    else
    {
        printf("\nmalloc failed\n");
        return NULL;
    }
    }
    //trim the arraylist if it's capacity is larger than its current size
    ArrayList *trimArrayList(ArrayList *list){
    int i;
    char **newarray = NULL;
    //trim length only if list->capacity is greater than list->size
    if (list->capacity <= list->size )
        return list;
    //create new (smaller) array to hold elements of the original arraylist
    newarray = malloc(sizeof(char*)*list->size);
    if (newarray != NULL){
    //transfer elements of old array into new array
    for (i=0; i<list->size; i++){
        strcpy(newarray[i], list->array[i]);
    }
    //inform user of change
    printf("-> Trimmed ArrayList to size %d", list->size);
    //free memory associated with old array
    for (i=0; i<list->size; i++){
        free(list->array[i]);
    }
    //set the old array equal to the newer trimmed array
    list->array = newarray;
    //update capacity
    list->capacity = list->size;
    return list;
    }
    else{
        printf("\nmalloc failed\n");
        return NULL;
    }}
    Any help will be greatly appreciated.
    Last edited by blackfox_1109; 02-01-2014 at 10:56 AM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Please indent your code properly. It can help if you use a blank line to separate logical sections of code, especially function definitions.

    Quote Originally Posted by blackfox_1109
    Right now I am using malloc on a new array and then transferring the elements of the original array to the new array, freeing the original array, and then reassigning it to the new array so it's size and capacity are either bigger or smaller than the original. I feel like there has to be a simpler way to do this with either realloc or calloc, but I cant find sufficient information on either online. Would I be able to use either to make this easier and the code cleaner?
    Instead of:
    Code:
    //Expand arraylist to new size
    ArrayList *expandArrayList(ArrayList *list, int length){
    int i;
    char **newarray = NULL;
    //find how many elements are currently in the array
    int arrsize = sizeof(list->array)/sizeof(list->array[0]);
    //create a new (larger) array to store the contents of the old array
    newarray = malloc(sizeof(char*)*length);
    //dont do anything if the length is smaller than the current capcity
    //or if the list was NULL
    if (length <= list->capacity)
        return NULL;
    if (list == NULL)
        return NULL;
    //make sure malloc was successful
    if (newarray != NULL){
    //copy the contents of list->array into newarray
    for (i=0; i<length; i++){
    strcpy(newarray[i], list->array[i]);}
     
    //free the orginal array, since it has been copied over to the new array
    for(i=0; i<list->capacity; i++){
            free(list->array[i]);
            }
    free(list->array);
    //set list->array to point to the newly created array
    list->array = &newarray;
    //let user know the function was successful
    printf("-> Expanded ArrayList to size %d", length);
    //set new size and capacity if they were changed
    list->size = arrsize;
    list->capacity = length;
    //return the pointer to
    return list;
    }
    //if malloc was unsuccessful
    else
    {
        printf("\nmalloc failed\n");
        return NULL;
    }
    }
    I would expect something like:
    Code:
    // Expand arraylist to new size
    ArrayList *expandArrayList(ArrayList *list, int length) {
        int i;
        char **newarray = NULL;
        // find how many elements are currently in the array
        int arrsize = sizeof(list->array) / sizeof(list->array[0]);
    
        // dont do anything if the length is smaller than the current capcity
        // or if the list was NULL
        if (list == NULL)
        {
            return NULL;
        }
        if (length <= list->capacity)
        {
            return NULL;
        }
        newarray = realloc(list->array, sizeof(list->array[0]) * length);
        if (newarray != NULL)
        {
            list->array = newarray;
            // let user know the function was successful
            printf("-> Expanded ArrayList to size %d", length);
            // set new size and capacity if they were changed
            list->size = arrsize;
            list->capacity = length;
            return list;
        }
        else
        {
            printf("\nmalloc failed\n");
            return NULL;
        }
    }
    Instead of doing the memory allocation and then checking the parameters, I do the parameter checking first. (The computation of arrsize should also be moved to later, but I kept it as-is as it is not an error.) Notice that I check for list == NULL before I dereference list with list->capacity. Then, I use realloc.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Oct 2013
    Posts
    29
    Is freeing the original function entirely unnecessary because I am just sending it right back to the exact same addresses?

    And what is the format for realloc so that I could use it in the future with my other functions?

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by blackfox_1109
    Is freeing the original function entirely unnecessary because I am just sending it right back to the exact same addresses?
    In your original implementation, free(list->array) is necessary because you use malloc to allocate a new dynamic array. Using realloc, this is no longer necessary and would in fact be a mistake. The loop that loops to free(list->array[i]) is a mistake because you copied those pointers over to the new dynamic array, thus freeing them here means that the new dynamic array contains pointers that are no longer valid.

    Quote Originally Posted by blackfox_1109
    And what is the format for realloc so that I could use it in the future with my other functions?
    Your learning materials should contain a declaration of realloc that you can refer to. Or, if you are using a system with man pages, running man realloc might work. Or, you can search the Web.

    EDIT:
    Oh, actually, the loop that "copy the contents of list->array into newarray" is also wrong because you failed to allocate space for the pointers to point to. With strcpy, you did not copy pointers, but rather copied the contents of what the pointers pointed to.

    I suggest that you work on something simpler: try implementing an ArrayList struct for a 1D dynamic array of ints, or maybe a string struct. Doing 2D without having done 1D is harder than doing 1D and then 2D.
    Last edited by laserlight; 02-01-2014 at 11:39 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Transferring vector data to an array
    By bijan311 in forum C++ Programming
    Replies: 1
    Last Post: 02-11-2012, 12:30 PM
  2. Passing Array To Function & Display Array Contents
    By mcertini in forum C++ Programming
    Replies: 4
    Last Post: 12-10-2010, 01:32 PM
  3. Passing a character array to a function
    By Qchem in forum C Programming
    Replies: 3
    Last Post: 03-07-2005, 07:18 AM
  4. Reading Contents of Edit Control up to a Certain Character
    By maththeorylvr in forum Windows Programming
    Replies: 1
    Last Post: 02-19-2005, 06:26 AM
  5. passing a character array through a function
    By volk in forum C++ Programming
    Replies: 4
    Last Post: 04-06-2003, 05:47 PM

Tags for this Thread