0

I just wondered what is the proper C syntax in WHAT_GOES_HERE? below? I tried a number of things and it doesn't compile.

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

#define MAX_SZ 256
typedef char Name[MAX_SZ];

int main(int argc, char **argv) {
    Name *a = (Name *)malloc(10 * sizeof(Name));
    char *b[MAX_SZ] = (WHAT_GOES_HERE?)malloc(10 * sizeof(char[MAX_SZ]));
    printf("sizeof(%s) = %Zu\n", "a[3]", sizeof(a[3])); 
    // outputs "sizeof(a[3]) = 256"
    return 0;
}
Henry Bigelow
  • 313
  • 1
  • 10
  • 1
    Nothing: https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – Govind Parmar Nov 17 '18 at 00:58
  • Hmm! Has the opinion changed since K&R? On p. 167 they state: "The pointer returned by malloc or calloc has the proper alignment for the object in question, but it must be cast into the appropriate type, as in "int *ip; ip = (int *) calloc(n, sizeof(int));" – Henry Bigelow Nov 17 '18 at 01:04
  • when calling any of the heap allocation functions: `malloc` `calloc` `realloc`, 1) always check (!=NULL) the returned value to assure the operation was successful. 2) the returned type, in C, is `void*` which can be assigned to any pointer. Casting just clutters the code, making it more difficult to understand, debug, etc. – user3629249 Nov 17 '18 at 01:23
  • regarding: `typedef char Name[MAX_SZ];` and related statements: this is giving the keyword `char` a new meaning of `Name[ MAX_SZ ]` This 'can' be done' but is a very poor programming practice – user3629249 Nov 17 '18 at 01:24
  • from the compiler, regarding this statement: `printf("sizeof(%s) = %Zu\n", "a[3]", sizeof(a[3]));` `untitled2.c:17:12: warning: ISO C does not support the ‘Z’ gnu_printf length modifier [-Wformat=]` – user3629249 Nov 17 '18 at 01:26
  • then the parameters to `main()` are not going to be used, then the signature should be: `int main( void )` – user3629249 Nov 17 '18 at 01:27
  • typedef char Name[MAX_SZ] makes "Name" a synonym for char[MAX_SZ]. If you want to check, print sizeof(Name) and sizeof(char). – Henry Bigelow Nov 17 '18 at 01:37
  • 1
    @HenryBigelow: Yes, to some extent opinion has changed — see [Should I cast the return value from `malloc()`](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). I side with answers such as [this](https://stackoverflow.com/a/14879184/15168) or [this](https://stackoverflow.com/a/33047365/15168), but I learned C before `void` was a keyword and on a machine where the `char *` to a memory location was a different value from an 'anything else pointer' to the same location so the cast was crucial to getting the code to work at all (on anything other than strings). – Jonathan Leffler Nov 17 '18 at 01:54

1 Answers1

2

You ask 'what goes here' in:

char *b[MAX_SZ] = (WHAT_GOES_HERE?)malloc(10 * sizeof(char[MAX_SZ]));

You want a dynamically allocated pointer to an array of 10 fixed size arrays (of char).

The first problem is "what goes on the LHS of the = sign", because what you've defined is that b is an array of MAX_SZ pointers to char, which is not what you said you wanted.

So, you need:

char (*b)[MAX_SZ] = malloc(10 * sizeof(char[MAX_SZ]));

Now you can refer to b[0] through b[9] as arrays of MAX_SZ characters.

If you want to add a cast (but see the notes and links in my comment), you need to match the type on the left-hand side minus the variable name:

char (*b)[MAX_SZ] = (char (*)[MAX_SZ])malloc(10 * sizeof(char[MAX_SZ]));

I wouldn't post such contorted code without a test, so I created a simple one based on yours and the information above, and ran it under Valgrind and got a clean bill of health.

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

enum { MAX_SZ = 256 };

int main(void)
{
    /* Pass 1 */
    {
    char (*b)[MAX_SZ] = malloc(10 * sizeof(char[MAX_SZ]));
    strcpy(b[0], "The zeroth");
    strcpy(b[9], "The ninth and final element of the array");
    printf("From '%s' to '%s', all is well\n", b[0], b[9]);
    free(b);
    }

    /* Pass 2 */
    {
    char (*b)[MAX_SZ] = (char (*)[MAX_SZ])malloc(10 * sizeof(char[MAX_SZ]));
    strcpy(b[0], "The zeroth");
    strcpy(b[9], "The ninth and final element of the array");
    printf("From '%s' to '%s', all is well\n", b[0], b[9]);
    free(b);
    }

    return 0;
}

The output is boring (sorry):

From 'The zeroth' to 'The ninth and final element of the array', all is well
From 'The zeroth' to 'The ninth and final element of the array', all is well
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278