30 votes

Le vecteur a converti toutes les valeurs négatives en zéro

J'ai créé un vecteur de taille constante pour stocker les valeurs négatives, puis j'ai imprimé les valeurs et je n'ai obtenu que des zéros. Je veux juste savoir pourquoi il ne stocke pas les valeurs négatives.

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v(5);
    v.push_back(-1);
    v.push_back(-2);
    v.push_back(-3);
    v.push_back(-4);
    v.push_back(-5);

    for (int i=0; i<5; i++)
       std::cout << v[i] << " ";  // All I got was zeroes
}

1 votes

C'est une joli bon exemple minimal reproductible . L'étape suivante aurait consisté à vérifier vos hypothèses, dont la plus pertinente est que std::vector<int> v(5) construit un vecteur vide avec une capacité de 5 éléments. Ceci est assez facile à tester en vérifiant la documentation ou d'imprimer le .size() du vecteur (bien que ce dernier point puisse impliquer une hypothèse sur la signification de la "taille", que vous devriez également tester).

1 votes

IMO, la manière la plus simple de déboguer ce problème est de vérifier la valeur du dernier élément, dans ce cas ce serait v.back() .

2 votes

Il est souvent judicieux de passer en boucle de 0 a size() (au lieu d'une valeur codée en dur) si vous voulez faire une boucle sur un conteneur (ou, mieux encore, utiliser for (int i: v) ) - cela permet de repérer plus facilement les bogues comme celui-ci et d'augmenter plus facilement la taille du conteneur, si vous souhaitez le faire un jour.

53voto

Bathsheba Points 23209

C'est parce que push_back met nouveau à la fin du vecteur.

Vous pouvez voir l'effet en lançant i a 9 : les nombres négatifs occuperont v[5] a v[9] .

Rédaction

std::vector<int> v{-1, -2, -3, -4, -5};

est une solution particulièrement élégante.

7 votes

@SuhailAkhtar : Ce n'est pas du tout une mauvaise question : Java le fait dans l'autre sens, où l'argument du constructeur définit l'élément capacité .

0 votes

Je pensais que la taille était fixe et qu'il n'était pas possible de la dépasser, mais qu'il fallait ajouter de nouveaux éléments à la capacité requise. Je me suis trompé.

2 votes

@SuhailAkhtar cette restriction (taille maximale fixée au moment de l'exécution) est correcte pour réseau s. La flexibilité accrue des vecteurs, combinée à leur temps d'exécution (généralement) réduit, les rend si populaires par rapport au type de tableau "classique".

25voto

lubgr Points 29224

Le constructeur que vous invoquez remplit les 5 premiers éléments avec des zéros, voir ici (n° 3 dans la liste des surcharges) :

Construit le conteneur avec le nombre d'instances de T insérées par défaut.

(où l'"instance insérée par défaut" d'une int est de 0). Ce que vous auriez voulu, c'est

std::vector<int> v;

v.reserve(5); /* Prevent unnecessary allocations as you know the desired size. */

v.push_back(-1);
/* ... */

Une alternative utilisant l'appel au constructeur d'origine est

#include <numeric>

std::vector<int> v(5);

std::iota(v.rbegin(), v.rend(), -v.size());

bien que cela représente plus de travail que nécessaire, car chaque élément est d'abord construit par défaut, puis affecté à une nouvelle valeur.

12voto

Ruslan Points 1710

Il s'agit d'un cas où le Principe de sécheresse vous aiderait à comprendre votre erreur.

vector<int> v(5);

...

for(int i=0;i<5;i++)

Vous créez ici un tableau, pour lequel vous pensez réserver de la place pour 5 éléments. Ensuite, vous insérez ces 5 éléments. Ensuite, vous voulez imprimer le contenu de tout le tableau, mais au lieu d'écrire simplement v.size() , vous avez répété le 5 de sorte que votre code se lit maintenant comme suit : "Imprimer les cinq premiers éléments de v "au lieu de "Imprimer tous les éléments de v ".

Si vous écriviez plutôt ce que vous voulez dire, vous verriez que le tableau a en fait 10 éléments, et non 5.

BTW, depuis C++11, vous pouvez boucler sur tous les éléments de manière plus directe :

for(int x : v)

ou, si les éléments sont d'un type plus coûteux en termes de copie, vous pouvez utiliser des références aux éléments, même auto -les références de type :

for(auto& x : v)

Cette nouvelle for -La syntaxe de la boucle est appelée basé sur la gamme for boucle .

6voto

hiimdaosui Points 211

Vous pouvez considérer le vector une version flexible du tableau primitif en C/C++. Lorsque vous initialisez un vector avec une taille n , le construit vector a une taille de n (ou peut-être plus grand dans la mémoire, mais vous ne le savez pas puisque c'est implicitement géré par le compilateur). Notez qu'ici n représente le nombre d'entrées, mais pas l'utilisation réelle de la mémoire (c'est-à-dire les octets). Si vous ne l'initialisez pas avec un paramètre de taille, la fonction vector est vide avec une taille de 0, mais dans la mémoire, elle aurait une taille implicite par défaut.

Supposons que votre vector a la taille 5. Et vous voulez push_back() dans un autre élément, alors le vector réaffectera en interne l'ensemble du tableau dans un nouvel emplacement mémoire qui pourra contenir toutes les anciennes entrées plus la nouvelle. Vous n'avez donc pas besoin de réallouer la mémoire manuellement, comme vous devez le faire en C.

Ici, dans votre exemple, pour remplir ces 5 entiers négatifs dans votre vector Il y a plusieurs façons de procéder.

1) Vous pouvez initialiser un vector sans en préciser la taille. Ensuite, vous pouvez insérer chaque élément que vous souhaitez.

vector<int> v;
for (int i = -1; i >= -5; --i) {
    v.push_back(i);
}

2) Vous pouvez initialiser le vector avec ce paramètre de taille. Ensuite, attribuez-leur de nouvelles valeurs.

vector<int> v(5);
for (int i = 0; i < v.size(); ++i) {
    v[i] = -i;
}

3) Vous pouvez également initialiser le vector avec ces entrées lorsqu'il est construit.

    vector<int> v{-1, -2, -3, -4, -5};
or  vector<int> v = {-1, -2, -3, -4, -5};

0 votes

En C/C++ Il n'y a pas de array en C - uniquement des tableaux de style C.

0 votes

@Ruslan J'ai mentionné primitif réseau

0 votes

Dans ce cas, il ne devrait pas être en police monospaciale, puisqu'il ne s'agit pas d'un code dans ce cas.

0voto

Lorsque vous avez déclaré le vecteur avec

std::vector<int> v(5);

Vous avez fait v stockent cinq espaces de 4 octets en mémoire (en supposant qu'un int = 4 octets sur votre système), et par défaut tous ces espaces de 4 octets stockent les bits représentant des 0. Ensuite, vous avez ajouté 5 ints supplémentaires (-1, -2, -3, -4, -5) à la fin du vecteur avec :

v.push_back(-1);
v.push_back(-2);
v.push_back(-3);
v.push_back(-4);
v.push_back(-5);

A ce stade, le vecteur a 10 éléments, les cinq premiers étant les ints inconnus qui se trouvent à stocker des 0 sur l'instance où vous avez exécuté le programme. Puisque votre boucle for imprime les cinq premiers éléments du vecteur, c'est la raison pour laquelle tous les 0 ont été imprimés.

3 votes

Il ne s'agit pas d'un hasard. std::vector a utilisé le constructeur pour initialiser les éléments qu'il stocke. Pour les types intégrés, l'initialisation de la valeur est définie comme étant la mise à zéro. Et le fait qu'il s'agisse de "4 octets" ou non n'a rien à voir avec le problème du PO, tout comme la représentation en bits de ces valeurs.

1 votes

@Ruslan Si la représentation des bits n'est pas pertinente, comment l'ordinateur stocke-t-il les 0 ?

2 votes

Quelle que soit la façon dont il stocke les zéros, le résultat du code de l'OP sera le même. Les bits n'entreraient en jeu que si le code comportait des opérations par bit, ce qui n'est pas le cas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X