1

I am trying to update string step by step in C. The code i tried is below:

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

int writech(char **text, char ch) {
    **text = ch;

    return 1;
}

char *write(int array[], size_t size) {
    char *string = (char*)malloc(sizeof(char)*(size+1));
    int i, n;

    for (i = 0; i < size; ++i) {
        n = writech(&string, '0' + array[i]);
        string += n;
    }

    return string;
}

int main() {
    int arr[] = { 1, 2, 3, 4, 5 };
    char *str = write(arr, sizeof(arr)/sizeof(arr[0]));

    printf("%s\n", str);

    return 0;
}

Here, write function should update string by calling other function and return updated string at the end. The code compiled and run successfully, though str (at the end of main) is empty after all. Actually, my task is to create string that contain table of some data and return it at the end. Pseudo code for my idea is below:

char *render_table() {
    char *table = malloc(sizeof table);

    write_header(table);
    write_row(table, some_data);
    write_row(table, some_data);
    write_footer(table)

    return table;
}

For implementing this pseudo code I wrote the above code, but not able to update passed string successfully. I know pointers are passed to function as copies, and passed memory of my string (writech(&string) to function, but string not updated still. What am i missing?

P.S. Tweaking with pointers is really struggling for me as beginner in C. What would you suggest?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Elgin Cahangirov
  • 1,932
  • 4
  • 24
  • 45
  • 2
    The `return string;` in `write()` returns the value after the several additions, ie: it returns the end of the string. You need to keep a copy of the original beginning of the string and return that instead. – pmg Oct 05 '20 at 13:03

3 Answers3

1

string is updated. The problem is the pointer string is updated and the information of the beginning of the string is lost. You have to hold the information.

One more point is that terminating null-character must be added to pass the buffer for %s (without specifying length to print).

Also note that casting results of malloc() in C is discouraged.

Try this:

char *write(int array[], size_t size) {
    char *string = malloc(sizeof(char)*(size+1));
    char *cursor = string;
    int i, n;

    for (i = 0; i < size; ++i) {
        n = writech(&cursor, '0' + array[i]);
        cursor += n;
    }
    writech(&cursor, '\0');

    return string;
}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
1

Seems to me that you are making this much more complicated than needed.

Simply do:

for (i = 0; i < size; ++i) {
    string[i] = '0' + array[i]);
}
string[i] = '\0';

If for some reason you really want to use the writech function, you can change it to:

void writech(char *text, char ch) {
    *text = ch;
}

and call it like:

for (i = 0; i < size; ++i) {
    writech(string + i, '0' + array[i]);
}
string[i] = '\0';

but it's really just making a simple task complex.

EDIT due to comment

If you (in your real code) don't know how many chars will be added by a function call, you simply do:

int writeSomethingA(char* str, ... other arguments ...)
{
    // update str, e.g. like str[0] = 'a'; str[1] = 'b';
    //                  or strcpy(str, "Some text");

    return NumberOfCharAdded;
}

(make similar B and C versions)

and call them like:

char* string malloc(....);
int idx = 0;

idx += writeSomethingA(string + idx, ... other arguments ...);

idx += writeSomethingB(string + idx, ... other arguments ...);

idx += writeSomethingC(string + idx, ... other arguments ...);

string[idx] = '\0';
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • thanks for suggestion. But your solution doesn't appeal my objective, since I don't know beforehand how many characters will be written. For loop in the code is just for representation for my real problem. See pseudo code for the real task. – Elgin Cahangirov Oct 05 '20 at 13:21
  • @ElginCahangirov What do you mean by: " I don't know beforehand how many characters will be written." ? The size is passed to the function – Support Ukraine Oct 05 '20 at 13:25
  • For example, write_header(table); function like this may write different number of characters based on some style or other conditions. That's way, I return `int` at the end of writech function and then use this int to increment pointer. – Elgin Cahangirov Oct 05 '20 at 13:28
  • yeah it is good idea to pass incremented pointer to function. But I think solution suggested above is neater. Thanks for your effors! – Elgin Cahangirov Oct 05 '20 at 13:46
  • 1
    @ElginCahangirov No problem - you are free to select the answer you prefer. Let me just recommend that you do **not** pass `&cursor`. There is no reason to pass it by address and it's making your code confusing and it hurts performance. Just pass `cursor` - it's sifficient for adding to the string. – Support Ukraine Oct 05 '20 at 14:05
0

For starters it is unclear why the function writech

int writech(char **text, char ch) {
    **text = ch;

    return 1;
}

has the first parameter with the type char ** instead of char *.

The function can be defined like

int writech( char *text, char ch ) {
    *text = ch;
    return 1;
}

Within the function write the pointer string is being changed in the for loop. So the function returns a pointer that does not point to the beginning of the allocated memory.

Also as you are using the conversion specifier %s to output the character array in main then the array shall contain a string. That is the array shall have contain the terminating zero character '\0'.

The function can be implemented the following way

char * write( const int array[], size_t size ) {
    char *string = malloc( size + 1 );

    if ( string != NULL )
    {
        char *p = string;

        while ( size-- ) {
            p +=  writech( p, '0' + *array++ );
        }

        *p = '\0';
    }

    return string;
}

And you should free the allocated memory before exiting main like

free( str );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335