Fuu
Fuu

Reputation: 29

C - function returns a pointer to a string from char matrix ONLY use pointers

I need to write a function called MakeString. The function returns a pointer to a string, which contains one word composed of each row of the small matrix in order, so that each line break will be expressed as a single space between the words In the string. (After the last word there will be no space.)

Inference: In the function there is no use of [], but executes by working with pointers.

Function. In addition, trips should be carried out with the voters, meaning that they will actually move to vote for each other

Whatever it takes, and will not stay in the same location all the time. The 'answer' that the function returns, which is a pointer, will be input into a pointer in MAIN.

I tried to do the function, but It NOT like instruction and not good...

#define SIZE 4
static char allocbuf[SIZE][];
static char *allocp = allocbuf;

char matrix[SIZE][SIZE]
{
    {U,N,T,E},
    {C,P,G,X},
    {D,L,A,B},
    {J,T,N,N}
};
char MakeString(int n)  /*return pointer to n charachters*/
{
    if (allocbuf + SIZE - allocp >=n)
    {
        allocp += n;
        return  allocp - n;
    }
    else
        return 0;
}

For example:

Small matrix:

U N T E

C P G X

D L A B

J T N N

pStr = UNTE CPGX DLAB JTNN

Thanks (:

Upvotes: 0

Views: 132

Answers (2)

David C. Rankin
David C. Rankin

Reputation: 84561

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.

Upvotes: 1

Barmar
Barmar

Reputation: 780974

You need to specify the size of allocbuf so it can hold the entire result:

char allocbuf[SIZE * (SIZE + 1)];

There's no need for allocp, because the array name will decay to a pointer when used in calculations. In MakeString, you need to loop over the rows and characters of matrix, copying them to allocbuf.

char *MakeString()
    for (int i = 0; i < SIZE; i++) {
        memcpy(allocbuf + i * SIZE, matrix + i, SIZE);
        if (i < SIZE - 1) {
            // write space between rows
            *(allocbuf + i * SIZE + SIZE) = ' ';
        } else {
            // write null at end
            *(allocbuf + i * SIZE + SIZE) = 0;
        }
    }
    return allocbuf;
}

The instructions don't mention the n argument to MakeString(), so I removed it.

Upvotes: 0

Related Questions