-1

I want to make dynamically allocated c-string table, but I think i don't understand the topic very well, could You explain it to me or correct my code?

#include <stdio.h>

    int main()
    {
        int i;
    char** t;
        t=(char**)malloc(16*sizeof(char*));

    for(i<0;i<100;i++)
    {
        *t[i]=(char*)malloc(16*sizeof(char));
    }

    return 0;
    }
  • 1
    [Don't cast malloc](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc), the cast is cruft from the 1970s that people have been copy-pasting ever since without thinking about it. – M.M May 20 '14 at 22:03

3 Answers3

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

int main(int I__argC, char *I__argV[])
   {
   int rCode=0;
   int i;
   char **t=NULL;
   size_t arraySize;

   /* Parse command line args. */
   if(2 != I__argC)
      {
      rCode=EINVAL;
      printf("USAGE: %s {dynamic array size}\n", I__argV[0]);
      goto CLEANUP;
      }

   arraySize=strtoul(I__argV[1], NULL, 0);
   if(0 == arraySize)
      {
      rCode=EINVAL;
      fprintf(stderr, "Cannot allocate a dynamic array of size zero.\n");
      goto CLEANUP;
      }

   /* Allocate a dynamic array of string pointers. */
   errno=0;
   t = malloc(arraySize * sizeof(*t));
   if(NULL == t)
      {
      rCode = errno ? errno : ENOMEM;
      fprintf(stderr, "malloc() failed.\n");
      goto CLEANUP;
      }

   memset(t, 0, arraySize * sizeof(*t));
   /* Initialize each pointer with a dynamically allocated string. */
   for(i=0; i<arraySize; i++)
      {
      errno=0;
      t[i]=strdup("A string");
      if(NULL == t[i])
         {
         rCode= errno ? errno : ENOMEM;
         fprintf(stderr, "strdup() failed.\n");
         goto CLEANUP;
         }
      }

CLEANUP:

   /* Free the array of pointers, and all dynamically allocated strings. */
   if(t)
      {
      for(i=0; i<arraySize; i++)
         {
         if(t[i])
            free(t[i]);
         }
      free(t);
      }

   return(rCode);
   }
Mahonri Moriancumer
  • 5,993
  • 2
  • 18
  • 28
  • If malloc() fails then it sets errno to ENOMEM, so the assignment `errno=ENOMEM;` does not make much sense. – Martin R May 20 '14 at 20:34
  • 1
    @MartinR malloc() is not required to set `errno`. If at all, it sets `errno` for *any* failure depends the implementation. – P.P May 20 '14 at 20:44
  • @BlueMoon: I got that from "man malloc" on OS X, and from http://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html: *"... Otherwise, it shall return a null pointer and set errno to indicate the error."* – Martin R May 20 '14 at 20:48
  • @MartinR That's POSIX behaviour, not ISO C. I said *not required to* i.e. the choice to set it or not is implementation's and can't berelied upon. – P.P May 20 '14 at 21:04
  • @MartinR, Didn't know that. Here is what SUSE SLES manpage says: _The Unix98 standard requires malloc(), calloc(), and realloc() to set errno to ENOMEM upon failure. Glibc assumes that this is done (and the glibc versions of these routines do this); if you use a private malloc implementation that does not set errno, then certain library routines may fail without having a reason in errno._ – Mahonri Moriancumer May 20 '14 at 21:07
  • @BlueMoon: You are right, I stand corrected. – Martin R May 20 '14 at 21:10
  • @MartinR; I have updated the answer (to handle both _private malloc implementations_ as well as for _Unix98 standard_). – Mahonri Moriancumer May 20 '14 at 21:12
  • This code seems inconsistent. If you're writing for POSIX or SUS you can count on `malloc()` setting `errno` to *something*, so the check for it seems redundant, and if you're *not* writing for POSIX or SUS, then you shouldn't be assuming that `strdup()`, `ENOMEM` or `EINVAL` will be defined, which you do assume. The question is just tagged `C`, so when you assume a particular implementation in your answer as you do, it would be good form to explicitly say so. Incidentally, what's with the idiosyncratic `I__argC` and `I__argV`? – Crowman May 20 '14 at 21:18
  • @PaulGriffiths, I agree with your assesment. As for `I__`, it's my thing. I have been writing 'sample code' for corporate APIs for many years. I use this style to indicate the general direction of data flow. `I__` prefix for `input` of data, `_O_` for `output` data (returning values through the parameter list), and 'IO_' when a parameter is used for both input and output. I didn't see any harm in using it here. – Mahonri Moriancumer May 20 '14 at 21:28
  • @MahonriMoriancumer Names starting with `_O` are reserved in C (§7.1.3-1: "All identifiers that begin with an underscore and ... an uppercase letter ... are always reserved for any use"); theoretically, you are not allowed to use them. In practice, there is low probability it will cause harm. – anatolyg May 21 '14 at 09:06
0

You should use variables for everything you want. For example, you allocate a memory for 16 elements of type char* and, as a result, you have an array with 16 elements, but then you are going from 0 to 100 ? Why ?

#include <stdio.h>

int main()
{
    int n = 16;
    int m = 16;
    // Allocate a memory for n elements of type char*
    char** t = (char**)malloc(n * sizeof(char*));
    for(int i = 0; i < n; ++i)
    {
        // For each element in array t - initialize with another array.
        // Allocate m elements of type char
        t[i] = (char*)malloc(m * sizeof(char));

        // Initialize
        for(int j = 0; j < m; ++j)
            t[i][m] = 'a';
    }

    // Print
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < m; ++j)
            printf("%c ", t[i][m]);
        printf("\n");
    }


    // Free allocated memory!
    for(int i = 0; i < n; ++i)
        free(t[i]);
    free(t);
    return 0;
}
grisha
  • 1,247
  • 1
  • 14
  • 20
-1

Your code can be corrected so that it can create 100X16 character table or table with 100 string of 16 char length.

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

int main()
{
    int i;
    int noOfStrings = 100;
    int eachStringLenght = 16;
     char** t;
    t=(char**)malloc(noOfStrings*sizeof(char*));

    for(i=0;i<noOfStrings;i++)
    {
        t[i]=(char*)malloc(eachStringLenght*sizeof(char));
    }

    return 0;
}
Sanzad
  • 14
  • 3
  • You need to `#include ` to safely call `malloc`; your compiler should warn about this. Some compilers suppress this warning if you cast malloc, which is one of the reasons [not to cast it](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – M.M May 20 '14 at 22:02