Search code examples
cchardynamic-memory-allocationc-stringsfunction-definition

adding zeros before string


zfill algorithm is supposed to work as follows:

  • zfill function accepts two parameters, a string and a number,
  • if string length is >= the number, then it doesn't have to add anything, and it returns a copy to the string,
  • else, malloc enough space and add zeros before the string.

I'm trying to understand why is this solution not correct, it has two warnings: 1st warning:

 for (i; i < zeros; i++) {
            s[i] = "0"; 
        }

"=": char differs in level of indirection from char[2]

2nd warning:

for (i; i < n; i++) {
            s[i] = str[i]; 
        }

buffer overrun while writing to s


    char* zfill(const char* str, size_t n) {
        if (str == NULL) {
            return NULL; 
        }
        char* s; 
        size_t length = strlen(str); 
        if (length >= n) {
            //it doesn't have to add anything, just malloc and copy the string
            size_t sum = length + 1u; 
             s = malloc(sum); 
            if (s == NULL) {
                return NULL; 
            }
            for (size_t i = 0; i < length; i++) {
                s[i] = str[i]; 
            }
            s[sum] = 0; 
        }
        else {
            // add zeros before strings
            size_t zeros = n - length; 
            size_t sum = n + 1u; 
             s = malloc(sum); 
            if (s == NULL) {
                return NULL; 
            }
            size_t i = 0;
            for (i; i < zeros; i++) {
                s[i] = "0"; 
            }
            for (i; i < n; i++) {
                s[i] = str[i]; 
            }
            s[sum] = 0; 
        }
        return s; 
    }
    
    int main(void) {
        char str[] = "hello, world!"; 
        size_t n = 40; 
    
        char* s = zfill(str, n); 
    
    
        free(s); 
        return 0; 
    }

EDIT: I've solved the problem this way:

char* zfill(const char* str, size_t n) {
    if (str == NULL) {
        return NULL; 
    }
    char* s; 
    size_t length = strlen(str); 
    if (length >= n) {
        //it doesn't have to add anything, just malloc and copy the string
        size_t sum = length + 1u; 
         s = malloc(sum); 
        if (s == NULL) {
            return NULL; 
        }
        for (size_t i = 0; i < length; i++) {
            s[i] = str[i]; 
        }
        s[sum-1] = 0; 
    }
    else {
        // add zeros before strings
        size_t zeros = n - length; 
        size_t sum = n + 1u; 
         s = malloc(sum); 
        if (s == NULL) {
            return NULL; 
        }
        size_t i = 0;
        for (i; i < zeros; i++) {
            s[i] = '0'; 
        }
        for (size_t j = 0; i < n; j++) {
            s[i++] = str[j]; 
        }
        s[sum-1] = 0; 
    }
    return s; 
}

and it works, but I don't know why I have this warning:

for (i; i < zeros; i++) {}

statement with no effect

but when I've debugged I've noticed that this statement has an effect, because it correctly copies the correct number of zeros. I don't know why I have this warning


Solution

  • so you have 3 major problems in your code :

    • it's s[i] = '0'; not s[i] = "0";
    • it's s[i] = str[i - zeros]; not s[i] = str[i]; as the value of the i will be 27 in your test case : so it make sense to say s[27] because its size is about 41 but it doesn't make sense to say str[27] as its size is only about 13 in your test case , so you had to map the value 27 of i to the value 0 to be convenient to use with str
    • i is deprecated in first part here for (i; i < zeros; i++) , so use for (; i < zeros; i++)instead of for (i; i < zeros; i++) , but it will not cause any problem if you keep it.

    and here is the full edited code :

    #include <stdint.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    char* zfill(const char* str, size_t n) {
        if (str == NULL) {
            return NULL;
        }
        char* s;
        size_t length = strlen(str);
        if (length >= n) {
            //it doesn't have to add anything, just malloc and copy the string
            size_t sum = length + 1u;
            s = malloc(sum);
            if (s == NULL) {
                return NULL;
            }
            for (size_t i = 0; i < length; i++) {
                s[i] = str[i];
            }
            s[sum] = 0;
        }
        else {
            // add zeros before strings
            size_t zeros = n - length;
            size_t sum = n + 1u;
            s = malloc(sum);
            if (s == NULL) {
                return NULL;
            }
            size_t i = 0;
            for (; i < zeros; i++) {
                s[i] = '0';
            }
            for (; i < n; i++) {
                s[i] = str[i - zeros];
            }
            s[sum] = 0;
        }
        return s;
    }
    
    int main(void) {
        char str[] = "hello, world!";
        size_t n = 40;
    
        char* s = zfill(str, n);
        printf("%s\n", s);
    
        free(s);
        return 0;
    }