82

I wrote this function that's supposed to do StringPadRight("Hello", 10, "0") -> "Hello00000".

char *StringPadRight(char *string, int padded_len, char *pad) {
    int len = (int) strlen(string);
    if (len >= padded_len) {
        return string;
    }
    int i;
    for (i = 0; i < padded_len - len; i++) {
        strcat(string, pad);
    }
    return string;
}

It works but has some weird side effects... some of the other variables get changed. How can I fix this?

10 Answers10

180

It might be helpful to know that printf does padding for you, using %-10s as the format string will pad the input right in a field 10 characters long

printf("|%-10s|", "Hello");

will output

|Hello     |

In this case the - symbol means "Left align", the 10 means "Ten characters in field" and the s means you are aligning a string.

Printf style formatting is available in many languages and has plenty of references on the web. Here is one of many pages explaining the formatting flags. As usual WikiPedia's printf page is of help too (mostly a history lesson of how widely printf has spread).

Jake
  • 2,401
  • 13
  • 23
Tom Leys
  • 17,070
  • 6
  • 38
  • 60
  • 4
    What if you want the string to be padded by another character besides spaces? Is there a way to do this w C's printf? – Peter Ajtai Oct 01 '11 at 18:01
  • It doesn't look like that is possible. (Did some Googling. Also the man page for `printf` doesn't seem to have any indication of such features.) – Victor Zamanian Feb 04 '12 at 12:54
  • @victor - http://www.cplusplus.com/reference/clibrary/cstdio/printf/ - see 'flags' section and 'width' section. – Tom Leys Feb 07 '12 at 22:31
  • 1
    @tom - yes, "the result is padded with blank spaces". So, it doesn't seem to be possible. As stated, the same information is available in the man page. Also, even though `printf` should behave mostly the same if not identically, this _is_ C, not C++. – Victor Zamanian Feb 08 '12 at 19:24
  • 1
    @Victor. Sorry, I thought you were replying to my answer, not Peter's subsequent question. Yes, you can only choose to pad with 0 or with ' ' nothing else. – Tom Leys Feb 19 '12 at 21:48
  • @Leys: Ah, okay. :-) No worries! – Victor Zamanian Feb 20 '12 at 22:41
  • @TomLeys the `-`flag will always pad with a space on the right side right?. can it pad with `0` on the right – Ratatouille Aug 22 '18 at 08:44
43

For 'C' there is alternative (more complex) use of [s]printf that does not require any malloc() or pre-formatting, when custom padding is desired.

The trick is to use '*' length specifiers (min and max) for %s, plus a string filled with your padding character to the maximum potential length.

int targetStrLen = 10;           // Target output length  
const char *myString="Monkey";   // String for output 
const char *padding="#####################################################";

int padLen = targetStrLen - strlen(myString); // Calc Padding length
if(padLen < 0) padLen = 0;    // Avoid negative length

printf("[%*.*s%s]", padLen, padLen, padding, myString);  // LEFT Padding 
printf("[%s%*.*s]", myString, padLen, padLen, padding);  // RIGHT Padding 

The "%*.*s" can be placed before OR after your "%s", depending desire for LEFT or RIGHT padding.

[####Monkey] <-- Left padded, "%*.*s%s"
[Monkey####] <-- Right padded, "%s%*.*s"

I found that the PHP printf (here) does support the ability to give a custom padding character, using the single quote (') followed by your custom padding character, within the %s format.
printf("[%'#10s]\n", $s); // use the custom padding character '#'
produces:
[####monkey]

MoonKnight
  • 23,430
  • 34
  • 134
  • 249
J Jorgenson
  • 1,295
  • 11
  • 19
  • It seems I have duplicated some else's posted answer here: [Varible sized padding in printf](http://stackoverflow.com/questions/4133318/varible-sized-padding-in-printf) – J Jorgenson Mar 16 '12 at 16:39
2

You must make sure that the input string has enough space to hold all the padding characters. Try this:

char hello[11] = "Hello";
StringPadRight(hello, 10, "0");

Note that I allocated 11 bytes for the hello string to account for the null terminator at the end.

Greg Hewgill
  • 828,234
  • 170
  • 1,097
  • 1,237
1

The argument you passed "Hello" is on the constant data area. Unless you've allocated enough memory to char * string, it's overrunning to other variables.

char buffer[1024];
memset(buffer, 0, sizeof(buffer));
strncpy(buffer, "Hello", sizeof(buffer));
StringPadRight(buffer, 10, "0");

Edit: Corrected from stack to constant data area.

Eugene Yokota
  • 90,473
  • 43
  • 204
  • 301
  • You're still passing a string literal... :P – Paige Ruten Nov 10 '08 at 01:33
  • you are copying too much. Hello is of type char[6] , but you try to copy 1024 bytes out of it. that can only fail. change it to read sizeof "Hello" instead of the second sizeof(buffer) – Johannes Schaub - litb Nov 10 '08 at 01:52
  • 1
    strncpy(buffer, "Hello", sizeof(buffer)); already fills the entire buffer with '\0', so your memset() is redundant. – Chris Young Nov 10 '08 at 06:24
  • @litb, strncpy: If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it. – Eugene Yokota Nov 10 '08 at 08:34
  • @Chris, memset after buffer is a habitual thing. I'll leave it in there. – Eugene Yokota Nov 10 '08 at 08:39
1

Oh okay, makes sense. So I did this:

    char foo[10] = "hello";
    char padded[16];
    strcpy(padded, foo);
    printf("%s", StringPadRight(padded, 15, " "));

Thanks!

1
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

using namespace std;

int main() {
    // your code goes here
    int pi_length=11; //Total length 
    char *str1;
    const char *padding="0000000000000000000000000000000000000000";
    const char *myString="Monkey";

    int padLen = pi_length - strlen(myString); //length of padding to apply

    if(padLen < 0) padLen = 0;   

    str1= (char *)malloc(100*sizeof(char));

    sprintf(str1,"%*.*s%s", padLen, padLen, padding, myString);

    printf("%s --> %d \n",str1,strlen(str1));

    return 0;
}
Naga
  • 422
  • 1
  • 7
  • 17
1
#include <stdio.h>
#include <string.h>

int main(void) {
    char buf[BUFSIZ] = { 0 };
    char str[] = "Hello";
    char fill = '#';
    int width = 20; /* or whatever you need but less than BUFSIZ ;) */

    printf("%s%s\n", (char*)memset(buf, fill, width - strlen(str)), str);

    return 0;
}

Output:

$ gcc -Wall -ansi -pedantic padding.c
$ ./a.out 
###############Hello
Tom Jowitt
  • 5,686
  • 11
  • 42
  • 60
Izya Budman
  • 34
  • 3
  • 4
0

The function itself looks fine to me. The problem could be that you aren't allocating enough space for your string to pad that many characters onto it. You could avoid this problem in the future by passing a size_of_string argument to the function and make sure you don't pad the string when the length is about to be greater than the size.

Paige Ruten
  • 157,734
  • 36
  • 172
  • 191
0

One thing that's definitely wrong in the function which forms the original question in this thread, which I haven't seen anyone mention, is that it is concatenating extra characters onto the end of the string literal that has been passed in as a parameter. This will give unpredictable results. In the example call of the function, the string literal "Hello" will be hard-coded into the program, so presumably concatenating onto the end of it will dangerously write over code. If you want to return a string which is bigger than the original then you need to make sure you allocate it dynamically and then delete it in the calling code when you're done.

0
#include<stdio.h>
#include <string.h>


void padLeft(int length, char pad, char* inStr,char* outStr) {
    int minLength = length * sizeof(char);
    if (minLength < sizeof(outStr)) {
        return;
    }

    int padLen = length - strlen(inStr);
    padLen = padLen < 0 ? 0 : padLen;

    memset(outStr, 0, sizeof(outStr));
    memset(outStr, pad,padLen);
    memcpy(outStr+padLen, inStr, minLength - padLen);
}
Ayodeji
  • 1
  • 2