Icon Ressource

[C] Join Funktionen - Einzelstrings aus einem Array in einem String verketten

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.
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;!"
Autor
german
Aufrufe
1.036
Erstellt am
Letzte Bearbeitung
Bewertung
0,00 Stern(e) 0 Bewertung(en)

Weitere Ressourcen von german

Oben Unten