9 Stimmen

Konvertieren Sie mit C ein dynamisch zugewiesenes int-Array so sauber wie möglich in eine durch Kommata getrennte Zeichenkette

Ich habe viel weniger Erfahrung mit C als mit höheren Sprachen. Bei Cisco verwenden wir C, und manchmal stoße ich auf etwas, das in Java oder Python leicht, in C aber sehr schwer zu bewerkstelligen wäre.

Ich habe ein dynamisch zugewiesenes Array von ganzen Zahlen ohne Vorzeichen, die ich in eine kommagetrennte Zeichenfolge für die Protokollierung konvertieren muss. Während die Integer wahrscheinlich nicht sehr groß sein, könnten sie konzeptionell überall von 0 bis 4.294.967.295 In Python, das ist eine kurze Zeile sein.

my_str = ','.join(my_list)

Wie elegant kann man das in C machen? Ich habe einen Weg gefunden, aber er ist ekelhaft. Wenn jemand einen schönen Weg kennt, es zu tun, bitte erleuchten Sie mich.

2 Stimmen

Können Sie die Art und Weise posten, wie Sie es in C gemacht haben?

2 Stimmen

Moment, join() ist eine Funktion der Klasse string!?

0 Stimmen

@BibedalShark: es ist C und nicht C++; keine Klasse

0voto

Edmund Punkte 10205

Leider wird es immer drei Fälle geben:

  • Leere Liste (keine Kommas, keine Einträge)
  • Eine Position (ohne Komma, eine Position)
  • Zwei oder mehr Positionen (n-1 Kommas, n Positionen)

Le site join Methode verbirgt diese Komplexität für Sie, weshalb sie so schön ist.

In C würde ich das tun:

for (i = 0; i < len; i++)
{
    if (i > 0)   /* You do need this separate check, unfortunately. */
        output(",");
    output(item[i]);
}

Wo output ist, wie auch immer Sie an die Zeichenkette anhängen. Es könnte so einfach sein wie strcat auf einen vorab zugewiesenen Puffer oder eine printf zu einem Strom (wie einem Speicherstrom, über den ich heute in Erstellen eines FILE *-Streams, der eine Zeichenkette ergibt :-).

Wenn Sie sich darüber ärgern würden, dass Sie diese Prüfung jedes Mal für alle i >= 1 durchführen müssen, könnten Sie das tun:

if (i > 0)
{
    output(item[0]);
    for (i = 1; i < len; i++)
    {
        output(",");
        output(item[i]);
    }
}

0 Stimmen

Verwenden Sie Duff's Device (siehe meine Antwort), um sowohl die Check-per-Loop- als auch die Duplizierung der Ausgabelogik zu vermeiden.

0voto

Michael Ekstrand Punkte 27071

Wenn Sie es in einer Datei haben wollen, ist die Antwort von Steven Schlansker gut.

Wenn Sie sie jedoch in eine Zeichenkette einfügen wollen, wird die Sache komplizierter. Sie können verwenden sprintf aber Sie müssen aufpassen, dass Ihnen der Platz in Ihrem String nicht ausgeht. Wenn Sie einen C99-kompatiblen snprintf (Linux, BSD, nicht Windows), sollte der folgende (ungetestete, nicht kompilierte) Code funktionieren:

char *buf = malloc(1024); /* start with 1024 chars */
size_t len = 1024;
int pos = 0;
int rv;
int i;
for (i = 0; i < n; i++) {
    rv = snprintf(buf+pos, len - pos, "%s%d", i = 0 ? "" : ",", my_list[i]);
    if (rv < len - pos) {
        /* it fit */
        pos += rv;
    } else {
        len *= 2;
        buf = realloc(buf, len);
        if (!buf) abort();
        i--; /* decrement i to repeat the last iteration of the loop */
    }
}
return buf;

Der Aufrufer muss dann die buf .

0 Stimmen

Warum mit 1024 beginnen und diese selbst aufteilen? Erlauben Sie dem Aufrufer, die Größe seines Puffers anzugeben, und behalten Sie sie in seiner Verantwortung. Arbeiten Sie mit dem, was Ihnen zur Verfügung steht.

0 Stimmen

Einverstanden. Wenn der Aufrufer freigibt, ist es sinnvoll, dass der Aufrufer auch allokiert.

0voto

ipeev Punkte 147
void join(int arr[], int len, char* sep, char* result){
    if(len==0){
        *result='\0';
    } else {
        itoa(arr[0],result,10);
        if(len > 1){
            strcat(result,sep);
            join(arr+1,len-1,sep,result+strlen(result));
        }
    }
}

0voto

ggorlen Punkte 32765

Hier ist eine lineare Lösung, die einen exponentiell wachsenden Puffer zuweist (weniger Aufrufe von realloc (falls das eine Rolle spielt) für den Anrufer zu befreien. Testskript enthalten.

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void ensure(bool pred, char *msg, char *file, int line) {
    if (!pred) {
        fprintf(stderr, "%s:%d: %s", file, line, msg);
        exit(1);
    }
}

char *arr_to_s(int len, int *arr, char *sep) {
    size_t sep_len = strlen(sep);
    int result_capacity = 16 + sep_len;
    int result_len = 0;
    char *result = malloc(result_capacity);
    ensure(result, "malloc", __FILE__, __LINE__);
    result[0] = '\0';

    for (int i = 0; i < len; i++) {
        char num[16+sep_len];
        int previous_len = result_len;
        result_len += sprintf(num, i < len - 1 ? "%d%s" : "%d", arr[i], sep);

        if (result_len >= result_capacity) {
            result_capacity <<= 1;
            result = realloc(result, result_capacity);
            ensure(result, "realloc", __FILE__, __LINE__);
        }

        strcat(result + previous_len, num);
    }

    return result;
}

void run_basic_tests(void) {
    int tests[][4] = {
        {0},
        {0, 1},
        {0, 1, 2},
        {0, 42, 2147483647, -2147483648},
    };

    for (int i = 0; i < 4; i++) {
        char *s = arr_to_s(i + 1, tests[i], ", ");
        printf("[%s]\n", s);
        free(s);
    }
}

void run_intensive_tests(int n) {
    srand(42);

    for (int i = 0; i < n; i++) {
        int len = rand() % 2000;
        int test[len];

        printf("[");

        for (int j = 0; j < len; j++) {
            test[j] = rand() % 2000000000 - 1000000000;
            printf(j < len - 1 ? "%d," : "%d", test[j]);
        }

        puts("]");

        char *s = arr_to_s(len, test, ",");
        printf("[%s]\n", s);
        free(s);
    }
}

int main(void) {
    //run_basic_tests();
    run_intensive_tests(10000);
    return 0;
}

Testläufer:

#!/usr/bin/env bash

gcc -std=c99 -pedantic -Wall \
    -Wno-missing-braces -Wextra -Wno-missing-field-initializers -Wformat=2 \
    -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith \
    -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline \
    -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code \
    -Wlogical-op -Wfloat-equal -Wstrict-aliasing=2 -Wredundant-decls \
    -Wold-style-definition -Werror \
    -ggdb3 \
    -O0 \
    -fno-omit-frame-pointer -ffloat-store -fno-common -fstrict-aliasing \
    -lm \
    -o arr_to_s.out \
    arr_to_s.c

./arr_to_s.out > arr_to_s_test_out.txt
cat arr_to_s_test_out.txt | awk 'NR % 2 == 1' > arr_to_s_test_expected.txt
cat arr_to_s_test_out.txt | awk 'NR % 2 == 0' > arr_to_s_test_actual.txt
diff arr_to_s_test_expected.txt arr_to_s_test_actual.txt

Valgrind:

==573== HEAP SUMMARY:
==573==     in use at exit: 0 bytes in 0 blocks
==573==   total heap usage: 103,340 allocs, 103,340 frees, 308,215,716 bytes allocated
==573==
==573== All heap blocks were freed -- no leaks are possible

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X