Diverse Sprachen bieten eine Join Funktion, die Elemente eines Arrays mit angegebenen Trennzeichen in einem String verketten. Unten finden sich zwei mögliche Umsetzungen in C.
Die JoinCopy Funktion verkettet in einen übergebenen Puffer mit fixer Breite.
Die JoinAlloc Funktion verkettet in einen dynamisch allokierten Puffer.
Ausgabe:
Die JoinCopy Funktion verkettet in einen übergebenen Puffer mit fixer Breite.
Die JoinAlloc Funktion verkettet in einen dynamisch allokierten Puffer.
C:
#include <stdio.h>
#include <string.h> // JoinCopy, JoinAlloc
#include <stdbool.h> // JoinCopy, JoinAlloc
#include <stdlib.h> // JoinAlloc
// Sollte das Argument für strVec ein Pointertyp auf ein non-const char sein, kann es mit dem STRVEC_C Macro zum richtigen Typ gecastet werden.
#define STRVEC_C(nonconst) ((const char *const *const)(nonconst))
/** \brief Einzelstrings aus einem Vector in einem Puffer verketten
* \param strVec Vector von Pointern auf die Einzelstrings
* \param countVec Anzahl Pointer im Vector
* \param delims Trennzeichenstring der zwischen die Einzelstrings gesetzt werden soll
* \param buffer Puffer in den die Einzelstrings des Vectors kopiert werden
* \param bufSize Größe des Puffers
* \param pLength Pointer auf ein size_t, das die Länge des Strings zugewiesen bekommt (darf NULL sein)
* \return false bei Fehler, sonst true */
bool JoinCopy(const char *const *const strVec, const size_t countVec, const char *const delims, char *const buffer, const size_t bufSize, size_t *const pLength)
{
if (bufSize && buffer)
*buffer = '\0'; // Wert im Fehlerfall
if (pLength)
*pLength = 0U; // Wert im Fehlerfall
if (!strVec || !*strVec || !countVec || !delims || !buffer || !bufSize) // Plausibilitätsprüfungen
return false; // Fehler und raus
size_t len = strlen(*strVec), // Länge eines Einzelstrings
rem = bufSize - 1U; // verbleibende Puffergröße
if (len > rem) // falls die Länge des ersten Einzelstrings größer als die verbleibende Puffergröße ist
return false; // Fehler und raus
const size_t lenDelims = strlen(delims); // Länge des Trennzeichenstrings ermitteln
char *bufIt = strcpy(buffer, *strVec) + len; // ersten Einzelstring in den Puffer kopieren
rem -= len; // verbleibende Puffergröße um die Einzelstringlänge vermindern
if (pLength)
*pLength = len; // Länge zuweisen
for (const char *const *vecIt = strVec + 1, *const *const vecEnd = strVec + countVec; vecIt < vecEnd; ++vecIt) // für jeden weiteren Einzelstring im Vector
{
if (!*vecIt // wenn Nullpointer
|| lenDelims + (len = strlen(*vecIt)) > rem) // oder die Länge des Trennzeichenstrings + Einzelstrings größer als die verbleibende Puffergröße ist
return false; // Fehler und raus
bufIt = strcpy(strcpy(bufIt, delims) + lenDelims, *vecIt) + len; // Trennzeichen und Einzelstring an das Ende des bisherigen Strings anhängen
rem -= lenDelims + len; // verbleibende Puffergröße um die Länge des Trennzeichenstrings und die Einzelstringlänge vermindern
if (pLength)
*pLength += lenDelims + len; // Gesamtlänge aufaddieren
}
return true; // OK und beenden
}
/** \brief Einzelstrings aus einem Vector in einem allozierten Speicherbereich verketten
* \param strVec Vector von Pointern auf die Einzelstrings
* \param countVec Anzahl Pointer im Vector
* \param delims Trennzeichenstring der zwischen die Einzelstrings gesetzt werden soll
* \param pString Pointer auf einen Charpointer in dessen Speicherbereich die Einzelstrings des Vectors kopiert werden
* \param pLength Pointer auf ein size_t, das die Länge des Strings zugewiesen bekommt (darf NULL sein)
* \return false bei Fehler, sonst true */
int JoinAlloc(const char *const *const strVec, const size_t countVec, const char *const delims, char **const pString, size_t *const pLength)
{
if (pString)
*pString = NULL; // Wert im Fehlerfall
if (pLength)
*pLength = 0U; // Wert im Fehlerfall
if (!strVec || !*strVec || !countVec || !delims || !pString) // Plausibilitätsprüfungen
return false; // Fehler und raus
const size_t lenDelims = strlen(delims); // Länge des Trennzeichenstrings ermitteln
size_t len = strlen(*strVec), // Länge eines Einzelstrings
total = len, // Gesamtlänge
capacity = countVec * lenDelims + countVec * len + 512U; // Aus Performancegründen werden mehr als 512 Bytes vorab allokiert.
if (!(*pString = (char*)malloc(capacity)))
return false;
char *bufIt = strncpy(*pString, *strVec, len) + len; // ersten Einzelstring in den Speicherbereich kopieren
for (const char *const *vecIt = strVec + 1, *const *const vecEnd = strVec + countVec; vecIt < vecEnd; ++vecIt) // für jeden weiteren Einzelstring im Vector
{
if (!*vecIt) // wenn Nullpointer
{
free(*pString); // Speicher freigeben
*pString = NULL; // Pointer auf Null setzen
return false; // Fehler und raus
}
len = strlen(*vecIt);
const size_t req = total + lenDelims + len + 1U;
if (req > capacity)
{
char *tmp = (char*)realloc(*pString, (capacity = req << 1));
if (!tmp)
{
free(*pString); // Speicher freigeben
*pString = NULL; // Pointer auf Null setzen
return false; // Fehler und raus
}
*pString = tmp; // Speichererweiterung zuweisen
bufIt = *pString + total; // Speichererweiterung zuweisen, Iterator auf das bisherige Stringende setzen
}
bufIt = strncpy(strcpy(bufIt, delims) + lenDelims, *vecIt, len) + len; // Einzelstring an das Ende des bisherigen Strings anhängen
total += lenDelims + len; // Gesamtlänge aufaddieren
}
*bufIt = '\0'; // Nulltermiinierung setzen
if (pLength)
*pLength = total; // Gesamtlänge zuweisen
return true;
} // ACHTUNG: Reservierten Speicher in der aufrufenden Funktion freigeben!
int main(void)
{
const char *const vec[] = {"Hello", "World", "!"};
const char delims[] = ";";
char buf[512] = {0}, // Puffer für JoinCopy
*str = NULL; // Charpointer für JoinAlloc
size_t len = 0U; // Gesamtlänge des verketteten Strings
bool ret = false; // Rückgabewert der Funktionen
/* ~~~ JoinCopy ~~~ */
ret = JoinCopy( // Funktion aufrufen und Rückgabewert zuweisen
vec, // Vector von Pointern auf die Einzelstrings
sizeof(vec) / sizeof(*vec), // Anzahl Elemente im Vector
delims, // Trennzeichen
buf, // Puffer für den String
sizeof(buf), // Größe des Puffers
&len // Adresse der Variablen, der die Gesamtlänge zugewiesen wird (darf NULL sein)
);
if (ret) // OK, wenn der Rückgabewert true ist
printf("%5u \"%s\"\n", (unsigned)len, buf); // Länge und String ausgeben
/* ~~~ JoinAlloc ~~~ */
ret = JoinAlloc( // Funktion aufrufen und Rückgabewert zuweisen
vec, // Vector von Pointern auf die Einzelstrings
sizeof(vec) / sizeof(*vec), // Anzahl Elemente im Vector
delims, // Trennzeichen
&str, // Adresse des Charpointers, der für den String alloziert wird
&len // Adresse der Variablen, der die Gesamtlänge zugewiesen wird (darf NULL sein)
);
if (ret) // OK, wenn der Rückgabewert true ist
{
printf("%5u \"%s\"\n", (unsigned)len, buf); // Länge und String ausgeben
free(str); // String freigeben, da er alloziert wurde
}
return 0;
}
Ausgabe:
Code:
13 "Hello;World;!"
13 "Hello;World;!"