Acolchado de cuerdas en C

81

Escribí esta función que se supone debe hacer StringPadRight ("Hola", 10, "0") -> "Hola00000".

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;
}

Funciona pero tiene algunos efectos secundarios extraños ... algunas de las otras variables se modifican. ¿Cómo puedo arreglar esto?


fuente

Respuestas:

170

Puede ser útil saber que printf realiza el relleno por usted, utilizando% -10s como cadena de formato rellenará la entrada en un campo de 10 caracteres de largo.

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

saldrá

|Hello     |

En este caso, el símbolo - significa "Alinear a la izquierda", el 10 significa "Diez caracteres en el campo" y la s significa que está alineando una cadena.

El formato de estilo Printf está disponible en muchos idiomas y tiene muchas referencias en la web. Aquí hay una de las muchas páginas que explican los indicadores de formato. Como de costumbre, la página printf de WikiPedia también es de ayuda (principalmente una lección de historia de cuán ampliamente se ha extendido printf).

Tom Leys
fuente
4
¿Qué sucede si desea que la cadena se rellene con otro carácter además de los espacios? ¿Hay alguna manera de hacer esto con printf de C?
Peter Ajtai
No parece que eso sea posible. (Busqué en Google. Además, la página de manual de printfno parece tener ninguna indicación de tales características.)
Victor Zamanian
@victor - cplusplus.com/reference/clibrary/cstdio/printf - vea la sección 'banderas' y la sección 'ancho'.
Tom Leys
1
@tom: sí, "el resultado se rellena con espacios en blanco". Entonces, no parece posible. Como se indicó, la misma información está disponible en la página de manual. Además, aunque printfdebería comportarse casi igual, si no idénticamente, esto es C, no C ++.
Victor Zamanian
1
@Víctor. Lo siento, pensé que estabas respondiendo a mi respuesta, no a la pregunta posterior de Peter. Sí, solo puede elegir rellenar con 0 o con "nada más".
Tom Leys
42

Para 'C' hay un uso alternativo (más complejo) de [s] printf que no requiere malloc () o formato previo, cuando se desea un relleno personalizado.

El truco consiste en usar especificadores de longitud '*' (mínimo y máximo) para% s, más una cadena rellena con su carácter de relleno hasta la longitud máxima potencial.

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 

El "% *. * S" se puede colocar antes O después de su "% s", dependiendo del deseo de relleno IZQUIERDO o DERECHO.

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

Descubrí que PHP printf ( aquí ) admite la capacidad de dar un carácter de relleno personalizado, utilizando comillas simples (') seguidas de su carácter de relleno personalizado , dentro del formato% s.
printf("[%'#10s]\n", $s); // use the custom padding character '#'
produce:
[####monkey]

J Jorgenson
fuente
Parece que he duplicado la respuesta publicada de otra persona aquí: relleno de tamaño variable en printf
J Jorgenson
2

Debe asegurarse de que la cadena de entrada tenga suficiente espacio para contener todos los caracteres de relleno. Prueba esto:

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

Tenga en cuenta que asigné 11 bytes para que la hellocadena tenga en cuenta el terminador nulo al final.

Greg Hewgill
fuente
1

El argumento que pasó "Hola" está en el área de datos constantes. A menos que haya asignado suficiente memoria a la cadena char *, está invadiendo otras variables.

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

Editar: Corregido de la pila al área de datos constantes.

Eugene Yokota
fuente
Todavía estás pasando una cadena literal ...: P
Jeremy Ruten
estás copiando demasiado. Hello es de tipo char [6], pero intentas copiar 1024 bytes. que solo puede fallar. cámbielo para que lea sizeof "Hello" en lugar del segundo sizeof (búfer)
Johannes Schaub - litb
1
strncpy (búfer, "Hola", tamaño de (búfer)); ya llena todo el búfer con '\ 0', por lo que su memset () es redundante.
Chris Young
@litb, strncpy: Si el final de la cadena C de origen (que se indica con un carácter nulo) se encuentra antes de que se hayan copiado num caracteres, el destino se rellena con ceros hasta que se haya escrito un total de num caracteres en él.
Eugene Yokota
@Chris, memset tras búfer es algo habitual. Lo dejo ahí.
Eugene Yokota
1

Oh está bien, tiene sentido. Entonces hice esto:

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

¡Gracias!


fuente
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
fuente
No olvides liberar str1
Pierre-Louis Sauvage
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;
}

Salida:

$ gcc -Wall -ansi -pedantic padding.c
$ ./a.out 
###############Hello
Izya Budman
fuente
0

La función en sí se ve bien para mí. El problema podría ser que no está asignando suficiente espacio para que su cadena incluya tantos caracteres en ella. Puede evitar este problema en el futuro pasando un size_of_stringargumento a la función y asegurarse de no rellenar la cadena cuando la longitud esté a punto de ser mayor que el tamaño.

Jeremy Ruten
fuente
0

Una cosa que definitivamente está mal en la función que forma la pregunta original en este hilo, que no he visto a nadie mencionar, es que está concatenando caracteres adicionales al final del literal de cadena que se ha pasado como parámetro. Esto dará resultados impredecibles. En la llamada de ejemplo de la función, la cadena literal "Hola" estará codificada en el programa, por lo que presumiblemente si se concatena al final, se escribirá peligrosamente el código. Si desea devolver una cadena que sea más grande que la original, debe asegurarse de asignarla dinámicamente y luego eliminarla en el código de llamada cuando haya terminado.

usuario4478828
fuente
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
fuente