Struggling with C Strings and printf %s

Viewed 102

So I struggle since a long time with a (I guess simple) problem with strings in C.

I want to create a list of char pointers and allocate by malloc() each of them some memory to fill with a single random character. At last I want to sort them and build up a new string with strcat().

So in this code only the first part is shown with some testfunctions:

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

int main(int argc, char* argv[]) {
    if (argc < 2) {
        printf("Error, too few arguments!\n");
        return 0;
    }

    // initialize random generator
    srand((unsigned int)time(NULL));

    const int a = atoi(argv[1]);

    char *array[a];

    //--------------- generate random characters ----------------------------------------
    for (int i = 0; i < a; i++) {
        int r = rand() % 30 + 1;
        printf("%d ", r);

        array[i] = (char*)malloc(a + 1 * sizeof(char));

        sprintf(array[i], "%ls", &r);
        *(array[i] + 1) = '\0';
    }

    putchar('\n');
    printf("%d %d %d \n", *array[0], *array[1], *array[2]);

    char *array_2 = (char*) malloc(a * sizeof(char));

    strcat(array_2, *array);
    strcat(array_2, *(array + 1));
    strcat(array_2, *(array + 2));

    printf("Address array_2[0] : %p , value: %d \n", array_2, *array_2);
    printf("Address array_2[1] : %p , value: %d \n", &array_2[1], array_2[1]);
    printf("Address array_2[1] : %p , value: %d \n", &array_2[2], array_2[2]);

    // produces a lot a garbage and crap
    printf("array_2 with string : %s :\n", array_2);

    // rest of the code omitted because it is irrelevant to the issue
    return 0;
}

So, what I don't understand: Printing the characters separately works fine. If I want to print the whole thing as a string, I only get a noisy string of characters. How can I realize the idea?

Honestly, I don't get the problem - if I create a character array like char array[4] = {'a','b','c', '\0'} I can print the whole thing with "%s"... But in my program it is almost the same but doesn't work.

I would be glad if somebody could give me a hint!

2 Answers

Your code has several problems:

  • The dimensions of the arrays are wrong. The a strings in array will hold a random number from 0 to 30, so each requires at most 3 bytes (two digits and the null character), but you allocate a bytes. These numbers are unrelated. array_2 must hold a concatenation of all array strings, so it will be at most 2*a bytes long and it needs one extra byte for the null character at the end.
  • Your sprintf is wrong: sprintf(array[i], "%ls", &r) tries to interpret the address of the integer r as the address of a wide char array. (This really looks as if you had fiddled with the format and argument until the compiler was silent.) To print the number r to the string, use sprintf(array[i], "%d", r).
  • sprintf will already null-terminate your string, so there is no need to do that explicitly.
  • As Ruslan has already pointed out, your array_2 points to uninitialized memory. The function strcat requires a null-terminated string. You can make array_2 a valid empty string by setting the first char to the null char '\0'.

In order to fix your code, I suggest the following:

  • Make array an array of strings of size 3. Don't allocate them on the heap, but make them automatic variables on the stack, which is easier to manage.
  • When you create the number strings, keep track of how long they are. The *printf functions have a useful return value, namely the number of characters that were printed or written to a string / file. Use that length to allocate memory for array_2.
  • Initialize array_2 as valid, empty string, then strcat all array strings to array_2.
  • Do interesting stuff with array_2, then freethe allocated memory.

Here's the code for that:

int a = 8;
char array[a][3];
int len = 0;

for (int i = 0; i < a; i++) {
    int r = rand() % 30 + 1;

    printf("%d\n", r);
    len += sprintf(array[i], "%d", r);
}

char *array_2 = malloc(len + 1);

*array_2 = '\0';
for (int i = 0; i < a; i++) {
    strcat(array_2, array[i]);
}

printf("\"%s\"\n", array_2);
free(array_2);

char *array_2 = (char*) malloc(a * sizeof(char));

strcat(array_2, *array);

You've allocated array_2, not initialized it, and then you're appending *array to whatever garbage array_2 had. That garbage likely contains lots of control characters, printable characters and whatnot before a null char occurs, so you get all these characters on your console (possibly with occasional beeps).

Related