Thread: Arrays, and what not

  1. #1
    Registered User
    Join Date
    Feb 2010
    Posts
    50

    Arrays, and what not

    Hello All,

    I am new to this language, so please forgive my ignorance. I am wondering how I can resize a character array after a size has been initially set. I am looking to do something like this:

    Code:
    #define SIZE 10
    
    static char myarray[SIZE];
    
    void resize_my_array(unsigned int new_size) {
           myarray[new_size];
    }

    How can this be accomplished in c? Thanks in advance for any guidance
    or help!

  2. #2
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    You can't.

    What you can do is fake an array using malloc() and then use realloc() to resize it. This will require you to check the results of the malloc() and realloc() functions (they can fail), and to free() the memory when you're done.

  3. #3
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    An alternative to achieve this is to make a linked list, it's a bit more involved though but should be more effective if you want to manipulate it more later and do things like insertion and removal of elements and so on.

    In a linked list each element is not necessarily placed in consecutive order in memory and contains the data and a link to the next element (or both to the next and the previous).

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    You can resize an array created with malloc:
    Code:
    char *array = malloc(32*sizeof(char));
    Using realloc()
    Code:
    array = realloc(array,sizeof(char)*16));
    This won't affect array[0-15], but it will render array[16-31] out of bounds.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    Thank you everyone for your prompt responses. I am trying the following code below:

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    
    #define THESIZE 10
    
    void resize_myarray( unsigned int new_size );
    char *myarray;
    
    main (int ac, char **av[]) {
    	myarray = malloc(THESIZE * sizeof(char));
    
    	myarray = "0123456789";
    
    	printf("%d\n", sizeof(myarray));
    
    	resize_myarray(THESIZE * 2 * sizeof(char));
    
    	myarray = "";
    	myarray = "01234567890123456789";
    
    	printf("%d\n", sizeof(myarray));
    
    	exit(0);
    }
    
    void resize_myarray ( unsigned int new_size ) {
    	myarray = realloc( myarray, new_size );
    }
    and am getting the following output:
    ----------------------------------------
    -- $ ./a.exe
    -- 4
    -- Aborted (core dumped)
    ----------------------------------------


    I am having some trouble understanding...
    a) why the size of the array is 4 with the first call to print the size. I figured it would be 10.
    b) why I am unable to reset the value of myarray to a 20 character string after resetting the size of the array w/realloc

    Again, your help is much appreciated!

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    a) Because sizeof a pointer is sizeof a pointer, not an array. Usually, the size of a pointer on 32-bit system is 4, hence the 4.
    b) Because you are assigning a string literal to your pointer. A string literal is a pointer, hence you overwrite the old value returned from malloc (creating a leak). You later invoke undefined behavior by calling realloc on a pointer not returned from malloc, hence the crash.
    c) Use strcpy to copy strings (preferably strncpy; read the doc on that one).
    d) You MUST use free after using malloc to free the memory.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    Thanks. The only part I suppose I am misunderstanding (from b) is why overwriting the old value creates a leak. In any event, I am now trying the following:

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    
    #define THESIZE 10
    
    void resize_myarray( unsigned int new_size );
    char *myarray;
    
    main (int ac, char **av[]) {
    	myarray = malloc(THESIZE * sizeof(char));
    
    	strncpy(myarray, "0123456789", THESIZE * sizeof(char));
    
    	printf("%d\n", strlen(myarray));
    
    	free(myarray);
    	resize_myarray(THESIZE * 2 * sizeof(char));
    
    	strncpy(myarray, "01234567890123456789", (THESIZE * 2 * sizeof(char)));
    
    	printf("%d\n", strlen(myarray));
    
    	exit(0);
    }
    
    void resize_myarray ( unsigned int new_size ) {
    	myarray = realloc( NULL, new_size );
    }

    and am confused by my output...
    ----------------------------------------
    -- $ ./a.exe
    -- 10
    -- 22
    ----------------------------------------

    I understand the 10 string of output, but am confused by 22. I was expecting 20.

  8. #8
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    First, you should be aware that in C, strings are always terminated by a null byte (that is, a byte with the value 0). Thus for "0123456789" you need 11 bytes; 10 for the digits, one for the null byte.

    Next, strncpy() does not always create strings, despite its name. You should always null-terminate the “strings” it creates. That is, strncpy() should be used as follows:
    Code:
    char target[10];
    strncpy(target, "some long string", (sizeof target) - 1);
    target[(sizeof target) - 1] = 0;
    There are other ways (set target[9] to zero ahead of time, etc), but the basic idea is the same: strncpy() is not a safe string function. It requires extra help.

    Also: don't free() before you call realloc(). realloc() needs a pointer to allocated memory (or NULL) to resize. Passing a freed pointer is not good. Call free() only after you're completely done with the memory.

  9. #9
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    Thanks! I am now getting the expected output...
    ----------------------------------------
    -- $ ./a.exe
    -- string: 0123456789; length: 10
    -- string: 01234567890123456789; length: 20
    ----------------------------------------

    from the code:

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    
    #define THESIZE 10
    
    void resize_myarray( unsigned int new_size );
    char *myarray;
    
    main (int ac, char **av[]) {
    	myarray = malloc((THESIZE * sizeof(char)) + 1);
    
    	strncpy(myarray, "0123456789", ((THESIZE * sizeof(char)) + 1));
    	myarray[THESIZE * sizeof(char)] = 0;
    
    	printf("string: %s; length: %d\n", myarray, strlen(myarray));
    
    	resize_myarray(THESIZE * 2 * sizeof(char));
    
    	strncpy(myarray, "01234567890123456789", ((THESIZE * 2 * sizeof(char)) + 1));
    	myarray[THESIZE * 2 * sizeof(char)] = 0;
    
    	printf("string: %s; length: %d\n", myarray, strlen(myarray));
    
    	//free(myarray);
    	exit(0);
    }
    
    void resize_myarray ( unsigned int new_size ) {
    	myarray = realloc( NULL, new_size );
    }
    However, when I remove the comment in front of free, the program hangs. Any idea why? I figured that I am supposed to call free() to so that the memory attached to the myarray pointer is once again made available.

  10. #10
    Registered User
    Join Date
    Feb 2010
    Posts
    11
    hi, sorry for my english. i added some comment on your code..
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    
    #define THESIZE 10
    
    void resize_myarray (char *arr, unsigned int new_size );
    //char *myarray;
    
    main (int ac, char *av[]) {  //NOT char**av[]
    	
    	char *myarray; //NO global variables NO
    	myarray = malloc(THESIZE * sizeof(char));
    
    	//you can store max THESIZE-1 char because there is a \n at the end if the string.
    	strncpy(myarray, "012345678", THESIZE * sizeof(char));
    
    	printf("%d\n", (int)strlen(myarray)); //need cast to int
    
    	free(myarray);
    	
    	resize_myarray(myarray, THESIZE * 2 * sizeof(char));
    
    	//same problem...you can store THESIZE * 2 - 1 char
    	strncpy(myarray, "0123456789012345678", (THESIZE * 2 * sizeof(char)));
    
    	printf("%d\n", (int)strlen(myarray)); //need cast to int
    
    	exit(0);
    }
    
    void resize_myarray (char *arr, unsigned int new_size ) {
    	arr = realloc( NULL, new_size );
    }

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by ignazioc View Post
    hi, sorry for my english. i added some comment on your code..
    That's good except you also rearranged the code AND DID NOT TEST IT, since your strategy is flawed and will not work. Read my added comments to your changes.
    Code:
    void resize_myarray (char *arr, unsigned int new_size );
    //char *myarray;
    
    main (int ac, char *av[]) {  //NOT char**av[]
    	
    	char *myarray; //NO global variables NO
    /* in reality, almost all C programs use global variables, but
      you are right to try and minimize them */
    
        [..........]
    
    /* the problem is, you cannot reassign a local pointer non-locally: */
    void resize_myarray (char *arr, unsigned int new_size ) {
    	arr = realloc( NULL, new_size );
    /* arr now no longer refers to myarray and no changes made here will have any affect */
    }
    Either you
    1) leave myarray global,
    2) use the return value of resize_myarray()
    3) use a pointer to a pointer in resize_myarray()
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #12
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    Concerning post #11...
    Thanks, however the previous post (#9) had resolved the array sizing issues. Also, the global variable is intended as a solution in the event that this file has a corresponding header file, and the resize array function is called from another program. As the code exists in post #9, the array could be resized from another program any number of times provided there is a corresponding header file.

    In trying to mind cas' suggestion:
    don't free() before you call realloc()...Call free() only after you're completely done with the memory.
    I am still wondering why
    when I remove the comment in front of free, the program hangs.
    Last edited by nicoeschpiko; 02-16-2010 at 03:34 PM. Reason: grammer

  13. #13
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    @nicoeschpiko: you are wrong to use a NULL pointer here:

    Code:
    myarray = realloc( NULL, new_size );
    This will leak the memory previously assigned to myarray and assign it brand new memory, meaning you lose all your data too. Very bad.

    You actually don't need to use the return value of realloc, the functionality is just this:
    Code:
    realloc(myarray, new_size);
    the only real usefulness is if you get an out of memory error, myarray will not be changed *but* realloc will return a NULL pointer. So really the "best practice" with realloc is:
    Code:
    if (!realloc(myarray, new_size) {
             puts("Realloc failed!");
             [...other error handling...]
    }
    ! is negation, so !realloc() would be true if realloc returned NULL (false).

    This way you will know about the failure and myarray will not be changed to NULL, which it would be with this:
    Code:
    myarray=realloc(myarray,new_size);
    However, an out-of-memory error is pretty weird and would more or less render all that irrelevant. Just you should understand how the function works.
    Last edited by MK27; 02-16-2010 at 03:36 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  14. #14
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    Thanks again! So I now have the code:

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    
    #define THESIZE 10
    
    void resize_myarray( unsigned int new_size );
    char *myarray;
    
    main (int ac, char **av[]) {
    	myarray = malloc((THESIZE * sizeof(char)) + 1);
    
    	strncpy(myarray, "0123456789", ((THESIZE * sizeof(char)) + 1));
    	myarray[THESIZE * sizeof(char)] = 0;
    
    	printf("string: %s; length: %d\n", myarray, strlen(myarray));
    
    	resize_myarray(THESIZE * 2 * sizeof(char));
    
    	strncpy(myarray, "01234567890123456789", ((THESIZE * 2 * sizeof(char)) + 1));
    	myarray[THESIZE * 2 * sizeof(char)] = 0;
    
    	printf("string: %s; length: %d\n", myarray, strlen(myarray));
    
    	//free(myarray);
    	exit(0);
    }
    
    void resize_myarray ( unsigned int new_size ) {
    	if (!realloc( myarray, new_size )) {
    		printf("ERROR: unable to reallocate memory for 'myarray'\n");
    		exit(1);
    	}
    }

    However, I am still wondering why when I remove the comment in front of free(), the program prints the last line below:

    string: 0123456789; length: 10
    string: 01234567890123456789; length: 20
    Aborted (core dumped)
    Last edited by nicoeschpiko; 02-16-2010 at 03:52 PM.

  15. #15
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    That code runs okay for me, what operating system and compiler are you using? It should be fine.

    However, this is wrong:
    Code:
    main (int ac, char **av[]) {
    2nd param should be either **av or *av[], not **av[].


    Here's something you could use in place of the second strncpy():
    Code:
    strncpy(&myarray[THESIZE], "0123456789", (THESIZE+1));
    This copies into the middle of the array, leaving the first part unchanged (the outcome in this case is the same of course.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

Popular pages Recent additions subscribe to a feed