String Padding in C.


80

Ich habe diese Funktion geschrieben, die StringPadRight ("Hallo", 10, "0") -> "Hallo00000" ausführen soll.

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

Es funktioniert, hat aber einige seltsame Nebenwirkungen ... einige der anderen Variablen werden geändert. Wie kann ich das beheben?

c  string  padding 

Antworten:


169

Es kann hilfreich sein zu wissen, dass printf das Auffüllen für Sie übernimmt und% -10s verwendet, da die Formatzeichenfolge die Eingabe direkt in ein 10 Zeichen langes Feld auffüllt

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

wird ausgegeben

|Hello     |

In diesem Fall bedeutet das Symbol - "Links ausrichten", die 10 bedeutet "Zehn Zeichen im Feld" und das s bedeutet, dass Sie eine Zeichenfolge ausrichten.

Die Formatierung im Printf-Stil ist in vielen Sprachen verfügbar und enthält zahlreiche Referenzen im Internet. Hier ist eine von vielen Seiten, auf denen die Formatierungsflags erläutert werden. Wie üblich hilft auch die printf-Seite von WikiPedia (meistens eine Geschichtsstunde darüber, wie weit sich printf verbreitet hat).


4
Was ist, wenn die Zeichenfolge neben Leerzeichen mit einem anderen Zeichen aufgefüllt werden soll? Gibt es eine Möglichkeit, dies zu tun?
Peter Ajtai

Es sieht nicht so aus, als wäre das möglich. (Hat ein bisschen gegoogelt. Auch die Manpage für printfscheint keinen Hinweis auf solche Funktionen zu haben.)
Victor Zamanian

@victor - cplusplus.com/reference/clibrary/cstdio/printf - siehe Abschnitt 'Flags' und 'Breite'.
Tom Leys

1
@tom - ja, "das Ergebnis wird mit Leerzeichen aufgefüllt". Es scheint also nicht möglich zu sein. Wie bereits erwähnt, sind dieselben Informationen auf der Manpage verfügbar. Auch, obwohl printfsich verhalten sollte meist die gleichen , wenn nicht identisch, dies ist C, C ++ nicht.
Victor Zamanian

1
@Sieger. Entschuldigung, ich dachte, Sie antworten auf meine Antwort, nicht auf Peters nachfolgende Frage. Ja, Sie können nur wählen, ob Sie mit 0 oder mit '' nichts anderes auffüllen möchten.
Tom Leys

41

Für 'C' gibt es eine alternative (komplexere) Verwendung von [s] printf, für die kein malloc () oder keine Vorformatierung erforderlich ist, wenn eine benutzerdefinierte Auffüllung gewünscht wird.

Der Trick besteht darin, '*' Längenangaben (min und max) für% s sowie eine mit Ihrem Füllzeichen gefüllte Zeichenfolge bis zur maximalen möglichen Länge zu verwenden.

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 

Die "% *. * S" können vor oder nach Ihren "% s" platziert werden, je nachdem, ob Sie eine LINKE oder RECHTE Polsterung wünschen.

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

Ich habe festgestellt, dass PHP printf ( hier ) die Möglichkeit unterstützt, ein benutzerdefiniertes Füllzeichen mit dem einfachen Anführungszeichen (') gefolgt von Ihrem benutzerdefinierten Füllzeichen im% s-Format anzugeben.
printf("[%'#10s]\n", $s); // use the custom padding character '#'
produziert:
[####monkey]


Es scheint, dass ich die Antwort eines anderen hier dupliziert habe: Polster in verschiedenen Größen in printf
J Jorgenson

2

Sie müssen sicherstellen, dass in der Eingabezeichenfolge genügend Platz für alle Füllzeichen vorhanden ist. Versuche dies:

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

Beachten Sie, dass ich der helloZeichenfolge 11 Bytes zugewiesen habe , um den Nullterminator am Ende zu berücksichtigen.


1

Das Argument, das Sie "Hallo" übergeben haben, befindet sich im konstanten Datenbereich. Wenn Sie nicht genügend Speicher für char * string zugewiesen haben, werden andere Variablen überschrieben.

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

Bearbeiten: Vom Stapel zum konstanten Datenbereich korrigiert.


Sie übergeben immer noch ein String-Literal ...: P
Jeremy Ruten

Sie kopieren zu viel. Hallo ist vom Typ char [6], aber Sie versuchen, 1024 Bytes daraus zu kopieren. das kann nur scheitern. Ändern Sie es, um die Größe von "Hallo" anstelle der zweiten Größe von (Puffer) zu lesen
Johannes Schaub - litb

1
strncpy (Puffer, "Hallo", sizeof (Puffer)); Füllt bereits den gesamten Puffer mit '\ 0', sodass Ihr memset () redundant ist.
Chris Young

@litb, strncpy: Wenn das Ende der Quell-C-Zeichenfolge (die durch ein Nullzeichen signalisiert wird) gefunden wird, bevor num-Zeichen kopiert wurden, wird das Ziel mit Nullen aufgefüllt, bis insgesamt num-Zeichen darauf geschrieben wurden.
Eugene Yokota

@ Chris, Memset nach Puffer ist eine Gewohnheit. Ich werde es dort lassen.
Eugene Yokota

1

Oh okay, macht Sinn. Also habe ich das gemacht:

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

Vielen Dank!


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

Vergessen Sie nicht, 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;
}

Ausgabe:

$ gcc -Wall -ansi -pedantic padding.c
$ ./a.out 
###############Hello

0

Die Funktion selbst sieht für mich gut aus. Das Problem könnte sein, dass Sie nicht genügend Speicherplatz für Ihre Zeichenfolge zuweisen, um so viele Zeichen darauf aufzufüllen. Sie können dieses Problem in Zukunft vermeiden, indem Sie ein size_of_stringArgument an die Funktion übergeben und sicherstellen, dass Sie die Zeichenfolge nicht auffüllen, wenn die Länge größer als die Größe sein soll.


0

Eine Sache, die definitiv falsch in der Funktion ist, die die ursprüngliche Frage in diesem Thread bildet, die ich noch nicht erwähnt habe, ist, dass zusätzliche Zeichen am Ende des als Parameter übergebenen Zeichenfolgenliterals verkettet werden. Dies führt zu unvorhersehbaren Ergebnissen. Im Beispielaufruf der Funktion wird das Zeichenfolgenliteral "Hallo" fest in das Programm codiert, so dass vermutlich das Verketten am Ende des Programms den Code gefährlich überschreibt. Wenn Sie eine Zeichenfolge zurückgeben möchten, die größer als das Original ist, müssen Sie sicherstellen, dass Sie sie dynamisch zuweisen und sie dann im aufrufenden Code löschen, wenn Sie fertig sind.


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);
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.