If I understand your question, you want write a function to read the characters from matrix (a 2D array of char) into an allocated string placing a space between each rows worth of characters and returning the nul-terminated string back to the calling function. You need to do this using pointers and without array [index] notation.
To begin, your declaration of matrix is wrong. E isn't a character, it is a variable. 'E' is a character literal. (note the single-quotes) So a proper declaration of matrix would be:
char matrix[SIZE][SIZE] = { {'U','N','T','E'}, /* don't use globals */
{'C','P','G','X'}, /* declare in main and */
{'D','L','A','B'}, /* pass as a parameter */
{'J','T','N','N'} };
(note: simply char matrix[][SIZE] = {{...}}; is sufficient, where the number of rows will be sized based on your initialization)
As noted in the comment, avoid the use of global variables unless absolutely necessary. (very limited cases -- not here). Instead, declare matrix in the scope where it is required and pass matrix as a parameter to any function that needs to process the data. By contrast, defining is constant with #define is perfectly correct, and you should define constants as needed to avoid using magic-numbers in your code.
Since matrix is a 2D array, to pass it as a parameter, you must include the number of columns as part of the parameter passed. You can either declare the parameter as char matrix[SIZE][SIZE] or equivalently as char (*matrix)[SIZE] reflecting the fact that the first level of indirection is converted to a pointer to the first element on access. See: C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3) (paying attention to the 4-exceptions)
Within your makestring() function you must allocate storage of at least SIZE * SIZE + SIZE (space for each character + 3 spaces + the nul-terminating character). Assigning the starting address of your new block of memory to a pointer, and then creating a second pointer to the block will allow you to iterate over it, copying characters to it -- while preserving a pointer to the beginning.
Putting those pieces together, you could do something similar to:
char *makestring (char (*a)[SIZE])
{
char *str = malloc (SIZE * SIZE + SIZE), *p = str; /* allocate */
if (!str) { /* validate EVERY allocation */
perror ("malloc-str");
return NULL;
}
for (int i = 0; i < SIZE; i++) { /* for each row */
if (i) /* if row not 1st */
*p++ = ' '; /* add space */
for (int j = 0; j < SIZE; j++) /* for each char */
*p++ = *(*(a + i) + j); /* copy to str */
}
*p = 0; /* nul-terminate string */
return str; /* return pointer to allocated string */
}
(note: while not an error, C generally avoids the use of camelCase or MixedCase variable names in favor of all lower-case while reserving upper-case names for use with macros and constants.)
Putting it altogether in a short example, you could do:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 4
char *makestring (char (*a)[SIZE])
{
char *str = malloc (SIZE * SIZE + SIZE), *p = str; /* allocate */
if (!str) { /* validate EVERY allocation */
perror ("malloc-str");
return NULL;
}
for (int i = 0; i < SIZE; i++) { /* for each row */
if (i) /* if row not 1st */
*p++ = ' '; /* add space */
for (int j = 0; j < SIZE; j++) /* for each char */
*p++ = *(*(a + i) + j); /* copy to str */
}
*p = 0; /* nul-terminate string */
return str; /* return pointer to allocated string */
}
int main (void) {
char matrix[SIZE][SIZE] = { {'U','N','T','E'}, /* don't use globals */
{'C','P','G','X'}, /* declare in main and */
{'D','L','A','B'}, /* pass as a parameter */
{'J','T','N','N'} },
*str;
if ((str = makestring (matrix))) { /* validate call to makestring */
printf ("str: '%s'\n", str); /* output string */
free (str); /* free allocated memory */
}
}
(note: don't forget to free the memory you allocate. While it will be freed on program exit, get in the habit of tracking your allocations and ensuring all blocks you allocate are freed)
Example Use/Output
$ ./bin/makestring
str: 'UNTE CPGX DLAB JTNN'
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/makestring
==6576== Memcheck, a memory error detector
==6576== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6576== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==6576== Command: ./bin/makestring
==6576==
str: 'UNTE CPGX DLAB JTNN'
==6576==
==6576== HEAP SUMMARY:
==6576== in use at exit: 0 bytes in 0 blocks
==6576== total heap usage: 1 allocs, 1 frees, 20 bytes allocated
==6576==
==6576== All heap blocks were freed -- no leaks are possible
==6576==
==6576== For counts of detected and suppressed errors, rerun with: -v
==6576== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
allocbufsupposed to be? An array of strings? Will the strings have a fixed static (at compile-time) size? Or will they need to be dynamically allocated?MakeStringfunction doesn't "make" a string. And it doesn't return anything that can be used as a string either. And I really don't see the need for all that pointer arithmetic either, what's wrong with a simple index that's compared toSIZE?allocbufshould be an array of pointers really? And yourMakeStringfunction needs to allocate the correct size (not forgetting the string null-terminator) and then return the pointer?[]in an array declaration is in a function parameter or when declaring an array with an initialization list (the size comes from the number of items in the list).