2
votes

Allocation de mémoire pour une chaîne en C à l'aide de malloc

J'essaye d'allouer de la mémoire pour un tableau de chaînes en utilisant malloc. La taille de chaque chaîne n'est pas connue avant l'entrée de l'utilisateur, c'est ainsi que j'ai essayé d'allouer de la mémoire pour chaque élément du tableau.

J'ai des erreurs avec le code, mais je ne peux pas les comprendre ou ne peut pas les comprendre. J'obtiens une erreur concernant l'allocation. Quelqu'un peut-il me dire ce qui ne va pas à ce sujet?

bool read_strings(char * strings[], int n) 
{
    int i = 0;
    while (i<n)
    {
        char string[MAX_LENGTH];
        if (scanf("%s", string)!=1)
            return false;
        char* memory= (char*)malloc(sizeof(char)*strlen(string));
        if (memory == NULL)
            return false;
        memory = string;
        strings[i] = memory;
        i++;
    }
    return true;
}

Merci beaucoup!


9 commentaires

memory = string; ici vous venez d'écraser (de perdre) votre pointeur de mémoire alloué.


vous cherchez à faire un strcpy .


Pourquoi? Et comment résoudre ce problème?


mieux regarder strdup


avertissement scanf s'arrêtera au premier espace, ce n'est pas une ligne de lecture


Je ne connais pas ces fonctions, je ne suis donc pas autorisé à les utiliser.


quel est le séparateur entre les chaînes?


memory est une variable qui contient votre nouveau pointeur. memory = string attribue la valeur de string à la memory . Ce qui était dans la mémoire avant cela a disparu. Vous devez utiliser la bibliothèque de fonctions de chaîne pour copier une chaîne lorsque vous avez les pointeurs vers les chaînes. C'est le moyen standard de copier / déplacer des chaînes. Si vous ne pouvez pas les utiliser, vous devrez écrire votre propre strcpy . Vous pouvez en trouver la source sur les interwebs.


Comme une base de données, si vous avez un MAX_LENGTH , envisagez d'allouer statiquement MAX_LENGTH + 1 char s et perdez de l'espace lorsque les chaînes sont plus courtes. (Vous ne voudrez peut-être pas cela si MAX_LENGTH est grand.)


5 Réponses :


0
votes

Vous avez de nombreuses erreurs

  1. (char *) malloc (sizeof (char) * (strlen (string) ** + 1 **)) . Vous devez réserver de la mémoire à '\0'
  2. Très faux

    memory = string;

    Pour copier des chaînes, vous devez utiliser strcpy (la fonction correcte de nos jours est strncpy est plus sûre)


1 commentaires

@lurker c'était une erreur de copier-coller ... J'ai vu votre avertissement après avoir corrigé l'erreur. Merci quand même



2
votes

Au moins, vous devez remplacer

strings[i] = strdup(string)

par

char* memory= (char*)malloc(sizeof(char)*strlen(string));
if (memory == NULL)
    return false;
memory = string;
strings[i] = memory;

Notez que l'utilisation de scanf ("% s", string ) le séparateur entre la chaîne de lecture est l'espace


2 commentaires

J'aime ta réponse. Peut-être pour être des chaînes plus parfaites [i] = strndup (string, MAX_LENGTH);


@ ruirodrigues1971 Le problème n'est pas le strdup , c'est le scanf sans limitation



0
votes

Le problème est ici:

 strings[i] = strdup(string);

Vous perdrez de la mémoire si vous attribuez des chaînes à des pointeurs comme celui-ci.

Soit:

a ) Copiez la chaîne dans la mémoire nouvellement allouée en utilisant strcpy () ou strncpy (), assurez-vous également que vous avez suffisamment d'espace pour le caractère NULL \0

strings[i] = (char*)malloc(sizeof(char) * (strlen(string) + 1));
strcpy(strings[i], string);

b) Utilisez strdup (), qui est comme un mélange entre strcpy () et malloc (), cela crée juste assez d'espace pour votre chaîne et la copie dans un nouvel emplacement mémoire

char* memory = (char*)malloc(sizeof(char)*strlen(string));
memory = string; <<<
strings[i] = memory;


4 commentaires

Vous ne pouvez pas attribuer des chaînes aux pointeurs de cette manière. vous pouvez ...


Mais avec le code OP, il perdra de la mémoire. Je pensais juste que c'était la meilleure pratique.


Mais votre déclaration était très absurde et trompeuse car vous avez oublié d'ajouter pourquoi il ne devrait pas attribuer ainsi.


strdup est une fonction POSIX et ne fait pas partie du standard C; il peut ne pas être implémenté dans certains systèmes d'exploitation, (mais il est facile à dupliquer.)



-1
votes

Je pense que c'est ce que vous vouliez faire:

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

int read_strings(char * strings[], int n)
{
    int i = 0;
    char buffer[256] ={0}; /*a temp buffer of fixed max size for input */
    if(NULL == strings)
    {
        return 0 ;
    }

    for (i= 0; i<n; ++i)
    {
      if (fgets(buffer, 256,stdin)== NULL) /*safer then scanf - read input into the buffer*/
        return 0;
        strings[i]= malloc(sizeof(char)*(strlen(buffer)+1)); /* the char poiner in he i place will now point to the newly allocated memory*/
        strcpy(strings[i], buffer); /*copy the new string into the allocated memory now string[i] is pointing to a string*/
    }

return 1;
}
static void printStringsArray(const char* strArr[], size_t size)
{
    int i = 0;
    if(NULL == strArr)
    {
        return;
    }
    for(i = 0; i< size; ++i)
    {
        printf("%s", strArr[i]);
    }

}

 int main(void)
 {
    char * arr[3]; /*array of (char*) each will point to a string after sending it to the function */
    read_strings(arr,3);

    printStringsArray(arr,3);
    return 0;
 }


0 commentaires

0
votes

Pour avoir une mémoire tampon vraiment illimitée dans C , (ou limitée par la quantité de mémoire et un size_t ,) vous pouvez augmenter l'allocation de mémoire de manière incrémentielle.

#include <stdlib.h>  /* realloc free */
#include <stdio.h>   /* stdin fgets printf */
#include <string.h>  /* strcpy */
#include <assert.h>  /* assert */
#include <stdint.h>  /* C99 SIZE_MAX */
#include <stdbool.h> /* C99 bool */

/* Returns an entire line or a null pointer, in which case eof or errno may be
 set. If not-null, it must be freed. */
static char *line(void) {
    char temp[1024] = "", *str = 0, *str_new;
    size_t temp_len, str_len = 0;
    while(fgets(temp, sizeof temp, stdin)) {
        /* Count the chars in temp. */
        temp_len = strlen(temp);
        assert(temp_len > 0 && temp_len < sizeof temp);
        /* Allocate bigger buffer. */
        if(!(str_new = realloc(str, str_len + temp_len + 1)))
            { free(str); return 0; }
        str = str_new;
        /* Copy the chars into str. */
        strcpy(str + str_len, temp);
        assert(str_len < SIZE_MAX - temp_len); /* SIZE_MAX >= 65535 */
        str_len += temp_len;
        /* If on end of line. */
        if(temp_len < sizeof temp - 1 || str[str_len - 1] == '\n') break;
    }
    return str;
}

static bool read_strings(char * strings[], int n) {
    char *a;
    int i = 0;
    while(i < n) {
        if(!(a = line())) return false;
        strings[i++] = a;
    }
    return true;
}

int main(void) {
    char *strings[4] = { 0 }; /* C99 */
    size_t i;
    bool success = false;
    do {
        if(!read_strings(strings, sizeof strings / sizeof *strings)) break;
        for(i = 0; i < sizeof strings / sizeof *strings; i++)
            printf("%lu: <%s>\n", (unsigned long)i, strings[i]);
        success = true;
    } while(0); {
        for(i = 0; i < sizeof strings / sizeof *strings; i++)
            free(strings[i]);
    }
    return success ? EXIT_SUCCESS : (perror("stdin"), EXIT_FAILURE);
}

Je pense que c'est juste. Cependant, cela devrait apporter une pause; et s'ils ne frappaient jamais entrer? Si l'on a un MAX_LENGTH , alors envisagez d'allouer statiquement, en fonction de votre situation.

Edit: Il a également un temps d'exécution dans le pire des cas qui peut ne pas être souhaitable; si vous entrez des lignes vraiment arbitrairement grandes, utilisez une progression géométrique pour allouer de l'espace.


0 commentaires