0
votes

Est-il possible de définir une matrice de taille dans un appel de fonction C?

Le code ci-dessous est-il sûr à utiliser? D'une manière ou d'une autre, je pense que ce n'est pas une bonne façon de faire. Je sais qu'un meilleur moyen est Malloc (), Realloc (). Mais je veux comprendre où ce code possède le plus de risque. Comme le compilateur ne connaît pas la taille de l'allocation, comment la taille de la pile sera définie?

int array_call(int k)

{
   int temp[k];
   int = 0;
   int i = 0;
   for (i = 0;i<k;i++)
       {
         temp[i]=i;
       }
    return k;

}

int main()
{

int n;
scanf("%d", &n);
n=array_call(n);

}


8 commentaires

Ils s'appellent Array de longueur variable ou VLA, car


Les tableaux de longueur variable sont une caractéristique optionnelle de la norme ISO C et peut donc ne pas fonctionner sur certains compilateurs.


Souhaitez-vous afficher le code qui compile sans erreurs?


L'avez-vous essayé avec n = 10000000?


Si l'utilisateur entre dans un très grand nombre dans stdin , votre programme est susceptible de planter en raison d'un Overflow de pile .


Ce code permet également des nombres négatifs comme entrée. Attention avec ça ...


@PMG, Andreas Wenzel Merci, je n'étais pas au courant de cette fonctionnalité en C. Comme Stark a souligné qu'il est obligé d'échouer pour le grand n. Même Malloc () est également obligé d'échouer pour une très grande demande d'allocation. Mais il retournera un pointeur nul. Mais la fonction de réseau variable de longueur manipulée dans le compilateur? Y a-t-il un moyen de l'utiliser en toute sécurité. Quelqu'un peut-il expliquer ces questions?


Non, il n'y a aucun moyen d'utiliser la VLA en toute sécurité. Autre que dans les programmes de jouets, je préférerais MALLOC () et des amis ... Pour une raison quelconque, il a été changé de requis en C99 pour En option dans C11


3 Réponses :



1
votes

Il s'agit d'un exemple d'une matrice de longueur variable (VLA), où la taille de la matrice n'est pas connue avant l'exécution. Cette fonctionnalité a été introduite dans la révision de la langue de 1999, mais a été facultative lors de la révision de 2011.

Donc, le premier risque est que les VLAS ne sont pas universellement pris en charge - ce code peut ne pas compiler sur certaines plates-formes. Sur C2011 et plus tard, vous voudrez vérifier si la macro __ stdc_no_vla __ a été définie avant d'essayer de les utiliser, quelque chose comme xxx

le Deuxième risque principal est que les VLAS ne peuvent pas être arbitrairement importantes - de nombreuses implémentations (sinon la plupart) tentent d'allouer de l'espace VLA à partir de la pile et d'empiler a tendance à être limitée. Si k est trop grand 1 Vous obtiendrez probablement une sorte d'erreur d'exécution irrécupérable.

VLAS ne peut pas être déclaré au champ de fichier ou avec le < Code> statique mot-clé, ni des membres de struct ou Union types.


  1. La valeur exacte de "trop ​​grande" dépend de la plate-forme, du compilateur, du code source, etc.

1 commentaires

De plus, VLAS ne peut pas être initialisé (C11 6.7.9P3)



1
votes

Le code ci-dessous est-il sûr à utiliser?

NO.

de quelque manière que ce soit, je pense que ce n'est pas bon faire. Je sais qu'un meilleur moyen est Malloc (), Realloc (). Mais je veux comprendre où ce code possède le plus de risque.

Risque n ° 1: la fonctionnalité que vous comptez sur des tableaux de longueur variable, est facultative en C11 et plus tard, et absent (au moins non normalisé) dans C90. Seulement en C99 est-il à la fois standard et obligatoire. De nombreuses implémentations C vous rencontrerez de la mise en œuvre, mais il y a des éléments notables qui ne le font pas. Votre code ne compilera pas du tout sur ce dernier.

Risque n ° 2: C ne spécifie pas comment les VLAS automatiques sont implémentées, mais il est courant qu'ils soient alloués sur la pile. Dans de telles implémentations, il est relativement facile de causer l'échec du programme avec un débordement de pile en fournissant une valeur trop importante de N . Il y a généralement (beaucoup) plus d'espace disponible pour une allocation dynamique avec MALLOC () & co., Mais même s'il n'y avait pas, vous pouvez au moins détecter et récupérer à partir d'un Malloc () < / code> échec. Similaire s'applique à la possibilité que n soit donné en tant que nombre négatif.

Risque n ° 3: Vous utilisez une entrée d'utilisateur non validée de manière sensible. Il s'agit d'un échec majeur du protocole de programmation sécurisé.

comme compilateur ne sait pas La taille de l'allocation, comment la taille de la pile sera définie?

Vous supposez qu'il y a une pile, et que c'est là que vous ira le VLA. Ni n'est garanti. Il n'existe pas non plus d'exigence pour un comportement particulier dans ces implémentations où ces deux hypothèses tiennent. En pratique, cependant, le compilateur est raisonnablement susceptible d'allouer des membres VLA au sommet de la pile, au-dessus des membres non-VLA, et simplement d'ajuster le pointeur de pile de manière appropriée pour la valeur du N . C'est un peu plus délicieux s'il y a plusieurs VLAS, mais totalement faisable. Cela fait partie des problèmes liés.


2 commentaires

Pouvez-vous expliquer un peu plus loin: "Vous supposez qu'il y a une pile et que c'est là que le VLA ira. Ni est garanti pour un comportement particulier dans lesquels ces deux hypothèses sont tenues. " Dans quels cas, il n'y aura pas de pile alloué? Je veux comprendre cela de manière plus détaillée.


@Sourodepbasu, il n'y a pas beaucoup plus à dire. La pile d'appel est un concept de mise en œuvre, pas un concept de langue C. Il est possible de créer une implémentation C conforme qui ne s'appuie pas sur une pile d'appels. Il est encore plus possible et plausible parmi les implémentations de matériel de produits de base pour y avoir une pile d'appels, mais VLAS ne doit pas être alloué là-bas. Rien de tout cela n'est vraiment motivé par le code source C impliqué