web-dev-qa-db-fra.com

Attribution de chaîne avec malloc

Je suis nouveau en programmation en C et maintenant j'étudie les cordes. Ma question est: si j'alloue une chaîne en utilisant malloc (comme dans le code ci-dessous), le caractère NULL est-il automatiquement inséré à la fin de la chaîne? Je trouve une réponse dans une autre question ici, et il semble que le caractère NULL ne soit pas automatiquement inclus. Mais voici le problème: je sais que des fonctions comme strlen ne fonctionnent pas s'il n'y a pas le caractère NULL, et dans ce code, je l'utilise et cela fonctionne. Je pense donc qu'il y a \0 à la fin de ma chaîne, même si je ne l'écris nulle part. Quelle est la réponse?

Voici le code:

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

int main(int argc, char** argv) {
    char *stringa1;
    int n;
    int i;

    printf("How many characters in the string? ");
    scanf("%d", &n);

    stringa1 = (char*) malloc(n*sizeof(char));

    printf("Insert the string: ");
    scanf("%s", stringa1);

    free(stringa1);

    return 0;
}
6
FranzGoogle

malloc() renvoie un pointeur void* vers un bloc de mémoire stocké dans le tas. L'allocation avec malloc() n'initialise aucune chaîne, seulement de l'espace en attente d'être occupé. Pour ajouter un caractère de fin nul, vous devez soit le faire vous-même, soit utiliser une fonction comme scanf() , ce qui ajoute ce caractère pour vous. Cela dit, vous devez au préalable allouer de l'espace pour ce caractère \0.

Votre appel malloc() devrait être celui-ci à la place:

stringa1 = (char*) malloc((n+1)*sizeof(char)); /*+1 for '\0' character */

Remarque: Vous n'avez pas besoin de lancer le retour de malloc. Pour plus d'informations, lisez this .

Une autre chose à souligner est sizeof(char) est 1, Donc multiplier ceci dans votre appel malloc() n'est pas nécessaire.

Vous devez également vérifier si malloc() renvoie NULL. Cela peut être fait comme ceci:

if (stringa1 == NULL) {
    /* handle exit */

De plus, vous ne pouvez utiliser que strlen() sur une chaîne terminée par un caractère nul, sinon cela finit par être comportement non défini .

Une fois que scanf() est appelée et que stringa1 Contient des caractères, vous pouvez appeler strlen() dessus.

De plus, la vérification du retour de scanf() est également une bonne idée. Vous pouvez le vérifier comme ceci:

if (scanf("%d", &n) != 1) {
    /* handle exit */

Votre code avec ces modifications:

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

int main(void) {
    char *stringa1 = NULL;
    size_t n, slen;

    printf("How many characters in the string? ");
    if (scanf("%zu", &n) != 1) {
        printf("Invalid input\n");
        exit(EXIT_FAILURE);
    }

    stringa1 = malloc(n+1);
    if (stringa1 == NULL) {
        printf("Cannot allocate %zu bytes for string\n", n+1);
        exit(EXIT_FAILURE);
    }

    printf("Insert the string: ");
    scanf("%s", stringa1);

    slen = strlen(stringa1);
    printf("String: %s Length: %zu\n", stringa1, slen);

    free(stringa1);
    stringa1 = NULL;

    return 0;
}
12
RoadRunner

si j'alloue une chaîne en utilisant malloc (comme dans le code ci-dessous), le caractère NULL est-il automatiquement inséré à la fin de la chaîne?

Non. malloc() renvoie un bloc de mémoire non initialisée.

Je sais que des fonctions comme "strlen" ne fonctionnent pas s'il n'y a pas le caractère NULL, et dans ce code, je l'utilise et cela fonctionne. Je pense donc qu'il y a '\ 0' à la fin de ma chaîne, même si je ne l'ai écrit nulle part.

scanf() insère l'octet nul ('\0') pour vous lorsque vous utilisez le spécificateur de format %s (en supposant que scanf() a réussi).

De man scanf() :

s Correspond à une séquence de caractères non blancs; le pointeur suivant doit être un pointeur vers l'élément initial d'un tableau de caractères suffisamment long pour contenir la séquence d'entrée et l'octet nul final ('\ 0'), qui est ajouté automatiquement. La chaîne d'entrée s'arrête à l'espace blanc ou à la largeur de champ maximale, selon la première éventualité.

(soulignement le mien).

Soit dit en passant, vous devez vérifier les erreurs pour les appels scanf() et malloc().

8
P.P

La définition de "chaîne" en C est ne séquence de caractères, terminée par un caractère nul.

Pour allouer de la mémoire à une chaîne, comptez les caractères (par exemple strlen) et ajoutez 1 pour ce caractère nul final.

Des fonctions comme scanf et strcpy ajoutent le caractère nul; une fonction comme strncpy ne fait pas toujours cela.

1
Paul Ogilvie

malloc renvoie le pointeur sur une étendue de mémoire non initialisée.

Si vous souhaitez que l'étendue de mémoire soit initialisée par des zéros, vous pouvez utiliser une autre fonction standard calloc au lieu de malloc.

Tenez compte du fait que généralement une telle question comme celle-ci

printf("How many characters in the string? ");

impliquent que le zéro final n'est pas compté. Vous devez donc allouer un octet de mémoire supplémentaire. Par exemple

stringa1 = ( char* )malloc( ( n + 1 ) *sizeof( char ) );

ou

stringa1 = ( char* )calloc( n + 1, sizeof( char ) );

Dans le dernier cas, vous pouvez appliquer la fonction strlen qui renvoie 0 car l'étendue de la mémoire est initialisée à zéro.

Cet appel de scanf

scanf("%s", stringa1);

est dangereux. Il vaut mieux utiliser fgets à la place. Par exemple

fgets( stringa1, n + 1, stdin );

Cette fonction peut ajouter la chaîne au nouveau caractère de ligne. Pour le supprimer de la chaîne, vous pouvez écrire

stringa1[strcspn( stringa1, "\n" )] = '\0';
1
Vlad from Moscow