Thread: How to allocate memory for an array of strings?

  1. #1
    Registered User
    Join Date
    Sep 2004
    Posts
    21

    How to allocate memory for an array of strings?

    I have the following declaration:

    char (*lines)[5];

    I need to allocate 10 strings, and each string is 5 characters long. I used the following but did not seem to work.

    lines = malloc(10 * sizeof(*lines));

    I don't know if the issue is with the declaration or the allocation.

    Thanks in advance.

  2. #2
    Registered User
    Join Date
    Oct 2015
    Posts
    28
    Usually strings vary in length, so an array of pointers to char is typically allocated,

    Code:
            char **ptr;
    
            if ((ptr = malloc(sizeof *ptr * 10)) == NULL)
                    handle_error;
    Storage for the strings is then allocated -- 6 bytes per string of length 5, to make room for the null character that marks the end of a string,

    Code:
            char *s;
    
            if ((s = malloc(6 * 10)) == NULL)
                    handle_error;
    Note: The expression (6*10) is equivalent to (sizeof "hello" * 10).

    The storage can then be written to,

    Code:
            int i;
    
            for (i = 0; i < 10; i++) {
                    ptr[i] = s;
                    s += sprintf(s, "hello") + 1;
            }
    Accessed,

    Code:
            int i;
    
            for (i = 0; i < 10; i++)
                    printf("%s\n", ptr[i]);
    And finally, cleaned up,

    Code:
            free(ptr[0]);
            free(ptr);

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > I need to allocate 10 strings, and each string is 5 characters long. I used the following but did not seem to work.

    It seems to work for me, what did you try?
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main()
    {
      char (*lines)[5];
      lines = malloc(10 * sizeof(*lines));
      strcpy(lines[0],"test");
      strcpy(lines[1],"word");
      strcpy(lines[2],"hey");
      strcpy(lines[3],"it");
      strcpy(lines[4],"does");
      for ( int i = 0 ; i < 5 ; i++ ) 
        printf("%s ", lines[i] );
      printf("\n");
      free(lines);
      return 0;
    }
    
    
    $ valgrind ./a.out
    ==4832== Memcheck, a memory error detector
    ==4832== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
    ==4832== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
    ==4832== Command: ./a.out
    ==4832== 
    test word hey it does 
    ==4832== 
    ==4832== HEAP SUMMARY:
    ==4832==     in use at exit: 0 bytes in 0 blocks
    ==4832==   total heap usage: 1 allocs, 1 frees, 50 bytes allocated
    ==4832== 
    ==4832== All heap blocks were freed -- no leaks are possible
    ==4832== 
    ==4832== For counts of detected and suppressed errors, rerun with: -v
    ==4832== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Sep 2004
    Posts
    21
    First, I want to thank you for your answer. Now my second question is, if I need a function that takes 'lines', how do I define the parameter and how I call the function with respect to passing argument 'lines'?

  5. #5
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Typically, you use
    Code:
    void takes_lines(char **const linearray, const size_t linecount)
    {
        /* The first line is at linearray[0],
         * first character of second line is linearray[1][0],
         * first character of third line is linearray[2][0],
         * and so on.
         * Only linearray[0] through linearray[linecount-1] are valid.
        */
    }
    The first const means the linearray variable is constant; the pointers to each line, and the contents of each line, are still modifiable. (If they are all constant, you can use const char *const *const linearray instead.)
    The second const means the linecount variable is constant.

    For a generic array of lines or strings, I tend to use (untested!)
    Code:
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    typedef struct {
        size_t max_count;
        size_t count;
        char **line;
    } lines;
    #define LINES_INIT { 0, 0, NULL }
    
    size_t lines_add(lines *const array, const char *const line)
    {
        const size_t linelen = (line) ? strlen(line) : 0;
        char *lineptr;
    
        if (!ref) {
            fprintf(stderr, "lines_add(): NULL array!\n");
            exit(EXIT_FAILURE);
        }
    
        if (ref->count + 1 >= ref->max_count) {
            const size_t max_count = (ref_count | 63) + 65; /* Or just ref_count + N, N >= 2 */
            void *const old = ref->line;
            size_t i;
    
            ref->line = realloc(old, max_count * sizeof *(ref->line));
            if (!ref->line) {
                free(old);
                fprintf(stderr, "lines_add(): Out of memory.\n");
                exit(EXIT_FAILURE);
            }
    
            ref->max_count = max_count;
            for (i = ref->count; i < max_count; i++)
                ref->line[i] = NULL;
        }
    
        lineptr = malloc(linelen + 1);
        if (!lineptr) {
            fprintf(stderr, "lines_add(): Out of memory.\n");
            exit(EXIT_FAILURE);
        }
        if (linelen > 0)
            memcpy(lineptr, line, linelen);
        lineptr[linelen] = '\0';
    
        /* Not necessary, I'm just paranoid */
        ref->line[ref->count + 1] = NULL;
    
        ref->line[ref->count] = lineptr;
        return ref->count++;
    }
    You can combine these using e.g.
    Code:
    int main(void)
    {
        lines many = LINES_INIT;
    
        lines_add(&many, "First line");
        lines_add(&many, "Second line");
        lines_add(&many, "Third line");
        lines_add(&many, "Fourth line");
        lines_add(&many, "Fifth line");
    
        /* Calls takes_lines(), passes references to all lines */
        takes_lines(many.line, many.count);
    
        /* Passes a reference to the first three lines */
        takes_lines(many.line, 3);
    
        /* Passes a reference to last two lines */
        takes_lines(many.line + many.count - 2, 2);
    
        /* Passes a reference to first half of all lines */
        takes_lines(many.line, many_count / 2);
    
        /* Passes a reference to latter half of all lines */
        takes_lines(many.line + many_count / 2, many_count - (many_count / 2));
    
        /* Done. */
        return EXIT_SUCCESS;
    }
    Last edited by Nominal Animal; 11-15-2015 at 10:30 PM.

  6. #6
    Registered User
    Join Date
    Sep 2004
    Posts
    21
    Code:
    char (*lines)[5];
    Code:
    lines = malloc(10 * sizeof(*lines)); // allocate 10 arrays and each array is 5 characters long
    now I need a function that takes entire 'lines' :
    Code:
    someFunc(char ?????, int num_of_array)  // I don't know how to declare ????? representing 'lines'
    {
        
    }
    ...

    and here I call the function:

    [cocde] someFunc(lines, 10); // and here I am not sure if I simply pass 'lines' or not.[/code]

    note that inside someFunc I will do the loop 10 times and retrieve each string that has 5 characters in it.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    The same way you declare it in main.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void someFunc(char (*lines)[5], int n)
    {
      strcpy(lines[0],"test");
      strcpy(lines[1],"word");
      strcpy(lines[2],"hey");
      strcpy(lines[3],"it");
      strcpy(lines[4],"does");
    }
    
    int main()
    {
      char (*lines)[5];
      lines = malloc(10 * sizeof(*lines));
      someFunc(lines,10);
      for ( int i = 0 ; i < 5 ; i++ )
        printf("%s ", lines[i] );
      printf("\n");
      free(lines);
    
      // This works too
      char array[10][5];
      someFunc(array,10);
      for ( int i = 0 ; i < 5 ; i++ )
        printf("%s ", array[i] );
      printf("\n");
    
      return 0;
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Sep 2004
    Posts
    21
    Thank you Salem and others for helping. My question was answered by you wonderful/helpful people. Case closed.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Allocate memory for array that contains struct. Help please.
    By Grigoris Savvas in forum C Programming
    Replies: 7
    Last Post: 04-03-2012, 12:14 PM
  2. Dynamically allocate memory to create 2D array
    By nonlinearly in forum C Programming
    Replies: 15
    Last Post: 11-10-2011, 02:22 AM
  3. Allocate memory for an Array
    By Coding in forum C++ Programming
    Replies: 3
    Last Post: 01-05-2008, 06:18 PM
  4. Dynamically allocate size of array for strings
    By Unregistered in forum C Programming
    Replies: 5
    Last Post: 05-04-2002, 05:06 PM
  5. How to allocate memory in multidimensional array?
    By Unregistered in forum C Programming
    Replies: 6
    Last Post: 10-15-2001, 10:07 AM

Tags for this Thread