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!
5 Réponses :
Vous avez de nombreuses erreurs
(char *) malloc (sizeof (char) * (strlen (string) ** + 1 **))
. Vous devez réserver de la mémoire à '\0'
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)
@lurker c'était une erreur de copier-coller ... J'ai vu votre avertissement après avoir corrigé l'erreur. Merci quand même
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
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
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;
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.)
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; }
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.
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 destring
à lamemory
. Ce qui était dans lamé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 proprestrcpy
. Vous pouvez en trouver la source sur les interwebs.Comme une base de données, si vous avez un
MAX_LENGTH
, envisagez d'allouer statiquementMAX_LENGTH + 1 char
s et perdez de l'espace lorsque les chaînes sont plus courtes. (Vous ne voudrez peut-être pas cela siMAX_LENGTH
est grand.)