I wanted to create a string padding function for the use of left-padding a binary representation with zeros, padding to the defined byte size. I first tried printf but that did not allow zero padding on a string and was not flexible.
I had come up with the following function:
char * strpadleft(char * string, char pad, size_t bytes) {
size_t ssize = strlen(string);
size_t bits = bytes * 8;
char *padded = (char *) malloc(bits + 1); /* Bit size + null terminator */
memset(padded, pad, bits); /* Fill contents with zeros, leave last null terminator*/
padded -= ssize + 1; /* Rewind back to offset*/
strncpy(padded, string, ssize); /* Replace for example bits 16->32 with representation*/
return padded;
}
/*Example: strpadleft("0100100001", '0', 4); */
Now unfortunately this returns simply the unpadded string (ex. 0100100001). Is my pointer arithmetic wrong, am I copying to the wrong location, or is there something else I missed that does not let this work?
There is major misconception and some other problems:
memset()does not changepaddedThat is, the variable in your function is not changed;
memset()just sets the data thatpaddedpoints to.The purported ‘reset’ operation
padded -= ssize + 1therefore invokes undefined behaviour by accessing memory that you did not allocate.Use:
instead of the two lines:
Using
strcpy()is safe because you know all the sizes.Note that
malloc()does not return initialized data, you cannot guarantee that the last allocated byte will be zero. You would have to usecalloc()for that.Note that the
memset()operation does NOT null terminate your string.Note that using
strncpy(), paradoxically, also does not guarantee null termination and indeed does not null terminate your string even if you got the start position correct. By contrast, usingstrcpy()does guarantee null termination.Working code
Note the revised interface – using
const char *for the first argument. (Thestaticjust gets the code to compile under my default compilation flags without a complaint of no prior declaration of the function. You would not use that for a library function declared in a header, of course.)Commentary
You really need to decide what would be appropriate behaviour if
ssize > bits(hint:assert()is not correct). Most probably, though, you would simply duplicate the original string. Note: it would absolutely NOT be acceptable to return a pointer to the original string. The function returns a pointer to a string that must be freed by the application; you must therefore always return an allocated string. Otherwise, your function becomes unusable; the code has to check whether the return value is the same as the argument and not release the return value if it is the same. Yuck!Quasi-fixed code
Demonstrating the lack of null termination in the original code:
With the same test program as before, and relying on undefined behaviour (there was no guarantee that the byte after the X would be a null byte), I got:
Note that the ‘X’ was not overwritten by the
strncpy()! You could fix that withssize + 1, but why not just usestrcpy()…as already stated…