2
votes

joindre deux cordes avec Malloc

J'ai travaillé sur un problème de débutant en C pour essayer d'apprendre les bases de C. J'ai remarqué que le problème ci-dessous commencera à l'index de l'endroit où la dernière chaîne prend son envol et finira cette chaîne, mais ce que j'essaye à faire est de joindre les deux chaînes ensemble.

Quelqu'un peut-il m'indiquer la bonne direction? J'essaye de le faire sans réallocation pour apprendre xp.

char *string_dup(char *src)
{
  int len = strlen(src);
  char *src2 = malloc(len + 1);
  int i;
  for(i = 0; i < len; i++){
    *(src2 + i) = *(src + i);
  }
  *(src2 + len )='\0';
  return src2;
}

void *resize_memory(void *ptr, int old_size, int new_size)
{
    char *d = (char*)ptr;
    d = malloc(new_size);
}


char *url = string_dup("http://");
char *path = string_dup("website.com/");
int url_length = string_length(url);
int path_length = string_length(path);

int new_length = url_length - 1 + path_length;
char *new_url = resize_memory(url, url_length, new_length);
char *p = new_url + url_length;


while (*path != '\0') {
    *p = *path;
    p++;
    path++;
}

printf("Full path string: %s\n", new_url);

c

11 commentaires

L'exercice est-il ici pour réimplémenter strdup ? Je veux juste comprendre l'objectif.


Remarque: il est conventionnel d'utiliser size_t au lieu de int pour les longueurs. Il s'agit d'un entier non signé car les tailles manifestement négatives n'ont aucun sens.


Il semble également que vous deviez activer beaucoup plus d'avertissements, même -Wall , car votre fonction resize_memory ne renvoie rien, mais promet de renvoyer void * < / code>. Ce code ne peut pas fonctionner tant que vous ne retournez pas d


N'oubliez pas de libérer cette mémoire!


resize_memory devrait probablement également copier l'ancien tampon dans le nouveau.


Demandez-vous ce que vous voulez exactement. Je pense que vous avez besoin d'un char * join (const char * s, const char * t) qui alloue strlen (s) + strlen (t) + 1 puis copie s (moins null) et t dans le tampon, peut-être en utilisant memcpy .


oh je sais que c'est un problème de débutant pour C. Je suis un débutant.


@ chargerfan619 Cherchez-vous à écrire une nouvelle fonction ou à modifier l'une des fonctions existantes que vous avez publiées ici?


J'essaye d'obtenir printf ("Chaîne de chemin complet:% s \ n", nouvelle_url); égal à "http: // website.com/" en modifiant la fonction resize_memory


OK, strlen (const char *) est une fonction de bibliothèque, mais qu'est-ce que string_length (char *)?


La fonction resize_memory ne renvoie rien. Soit vous souhaiterez changer la valeur de retour de void en char *, soit vous souhaiterez utiliser un double pointeur.


3 Réponses :


0
votes

Essayez quelque chose comme

char *url = string_dup("http://");
char *path = string_dup("website.com/");
size_t sTotal = strlen(url) + strlen(path) + 1u;
char *pStr = malloc(sTotal);
snprintf(pStr, sTotal, "%s%s", url, path);
free(url);
free(path);


0 commentaires

0
votes

J'ai joué un peu avec votre code puis j'ai trouvé cette solution. Cela vous permet de vous débarrasser de cette fonction string_dup () et de créer une fonction unique qui peut allouer / attribuer une nouvelle chaîne et ajouter une chaîne existante avec plus de données.

int
append_string(char **append_to, char *append_this) {
    char    *tmp;

    // You might want to check that append_this is not
    // NULL...

    if (*append_to == NULL) {
        *append_to = malloc(strlen(append_this) + 1);
        strcpy(*append_to, append_this);
    }
    else {
        // Some data already exists on the append_to buffer...
        //
        // If you want to only use malloc() then make a temporary
        // storage area and copy the append_to string there
        //
        if ((tmp = malloc(strlen(*append_to) + 1)) == NULL)
            return -1;
        strcpy(tmp, *append_to);

        // Free up and re-allocate append_to.
        //
        free(*append_to);
        *append_to = malloc(strlen(tmp) + strlen(append_this) + 1);

        if (! append_to) {
            fprintf(stderr, "Malloc error...");
            exit(EXIT_FAILURE);
        }

        // Do it with realloc
        //
        // No temporary buffer required:
        //
        //      *append_to = realloc(
        //          *append_to,
        //          (strlen(append_to) + strlen(*append_this) + 1)
        //      );
        //      if (! eppend_to) ...realloc error

        // Copy the data to the buffer and clean up.
        //
        sprintf(*append_to, "%s%s", tmp, append_this);
        free(tmp);
    }
}


/* In your main() or whatever... */

    char *url = NULL;
    char *path = NULL;

    // Since url and path are both NULL the
    // append string function will act like
    // your string_dup() function...
    append_string(&url, "http://");
    append_string(&path, "website.com/");

    // And not that url is not null it will be
    // resized and the path appended.
    append_string(&url, path);

    fprintf(stdout, "URL: %s\n", url);

    // Some housekeeping....
    if (url) free(url);
    if (path) free(path);
}

J'espère que c'est utile, je sais que c'est un peu différent de ce que vous aviez à l'origine, mais je pensais que je jouerais le jeu!


0 commentaires

2
votes

Problème avec le code OP:

Mauvaise taille

En supposant que string_length () est comme strlen () .

// *s1 is a prior allocated string, or NULL
 void ConcatenateString(char **s1, const char *s2) {
  char *joined = JoinStrings(*s1, s2);
  free(*s1);
  *s1 = joined;
}

Redimensionnement inefficace

char *JoinStrings(const char *s1, const char *s2) {
  size_t sz = (s1 ? strlen(s1) : 0) + (s2 ? strlen(s2) : 0) + 1;
  char *joined = malloc(sz);
  if (joined) {
    int len = snprintf(joined, sz, "%s%s", s1, s2);
    assert(len >= 0 && (unsigned) len < sz);  // Failure is very unexpected here.
  }
  return joined;
}

Je m'attendrais à quelque chose comme

// s1, s2 may be NULL.  A NULL is treated as if ""
char *JoinStrings(const char *s1, const char *s2) {
  size_t len1 = s1 ? strlen(s1) : 0;
  size_t len2 = s2 ? strlen(s2) : 0;
  char *joined = malloc(len1 + len2 + 1);
  if (joined) {
    memcpy(joined, s1, len1);
    memcpy(joined + len1, s2, len2);
    joined[len1 + len2] = '\0';
  }
  return joined;
}

Façons de joindre des chaînes avec realloc () avec allocation.

  1. Rechercher des longueurs.
  2. Allouer de la mémoire.
  3. En cas de succès, copiez la première, puis la deuxième chaîne. Ajoutez un \ 0.

Exemple de code:

// return failure status
bool resize_memory(void **ptr_addr, size_t old_size, size_t new_size) {
  void *new_ptr = NULL;
  if (new_size > 0) {
    new_ptr = malloc(new_size);
    if (new_ptr) {  // Out of memory, leave *ptr_addr alone
      return true;
    }
    size_t min_size = old_size < new_size ? old_size : new_size;
    memcpy(new_ptr, *ptr_addr, min_size);
  }
  free(*ptr_addr);
  *ptr_addr = new_ptr;  
  return false;
}

Ou via snprintf()

void *resize_memory(void *ptr, int old_size, int new_size) {
    char *d = (char*)ptr; // assign `d`
    d = malloc(new_size); // Why re-assigned `d`???
    // No use of old_size, new_size
    // No copying of existing data 
    // No freeing of old allocation  
}

Pour concaténer comme (* s1) + = s2

// int new_length = url_length - 1 + path_length;
int new_length = url_length + 1 + path_length;


0 commentaires