Problem bei C++ Programmcode

Gast #5297935
Lesenswert?

Hallo,

ich habe ein kleines Problem bei meinem C++ Code, es ist eine 
Übungsaufgabe, die folgendermaßen lautet:

1) Write  a  function  that  takes  a  vector<string>  argument  and 
returns  a vector<int>  containing  the  number  of  characters  in 
each  string.

2) Also find the longest and the shortest string and the 
lexicographically first and last string.

Ich beschränke mich vorerst auf Aufgabenteil 1).



Mein Quellcode sieht folgendermaßen aus:
1
struct vectorProperties
2
{
3
    vector<int> length;
4
    string shortest;
5
    string longest;
6
    string first;
7
    string last;
8
};
9

10
vector<int> get_length(vector<string>& v)
11
{
12
    if(v.size()==0) error("Vector contains no elements.");
13

14
    vector<int> length;
15
    for(int i=0; i<v.size(); ++i)
16
    {
17
        length.push_back(v[i].size());
18
    }
19
    return length;
20
}
21

22
vectorProperties getProps(vector<string>& v)
23
{
24
    vectorProperties vecProps;
25
    vecProps.length = get_length(v);
26
    /*
27
    vecProps.shortest = get_shortest();
28
    vecProps.shortest = get_longest();
29
    vecProps.shortest = get_first();
30
    vecProps.shortest = get_last();
31
    return vecProps;
32
    */
33
}
34

35
int main()
36
try{
37
    vector<string> v;
38
    v.push_back("Hallo");
39
    v.push_back("das");
40
    v.push_back("ist");
41
    v.push_back("ein");
42
    v.push_back("Testprogramm.");
43

44
    vectorProperties vecProps = getProps(v);
45
}
46
catch(exception& e){
47
    cerr << "error: " << e.what() << endl;
48
}
49
catch (...) {
50
    cerr << "exception\n";
51
}
Gast #5298011
Lesenswert?

balankoff schrieb:
> Es gab ja keine Warnungen oder Fehler vom Compiler, das ist es ja eben.
Also bei mir zeigt er an:
1
test2.cc: In function ‘std::vector<int> get_length(std::vector<std::__cxx11::basic_string<char> >&)’:
2
test2.cc:24:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
3
     for(int i=0; i<v.size(); ++i)
4
                  ~^~~~~~~~~
5
test2.cc:26:35: warning: conversion to ‘std::vector<int>::value_type {aka int}’ from ‘std::__cxx11::basic_string<char>::size_type {aka long unsigned int}’ may alter its value [-Wconversion]
6
         length.push_back(v[i].size());
7
                          ~~~~~~~~~^~
8
test2.cc: In function ‘vectorProperties getProps(std::vector<std::__cxx11::basic_string<char> >&)’:
9
test2.cc:42:1: warning: no return statement in function returning non-void [-Wreturn-type]
10
 }
11
 ^

Benutzt du "using namespace std"? Das ist schlecht:
https://stackoverflow.com/a/1452738
1
vector<int> length;
Du solltest std::size_t nutzen, denn int könnte zu klein sein für eine 
String-Länge. std::string::size() liefert einen std::size_t zurück, 
keinen int.
1
for(int i=0; i<v.size(); ++i)
Gleiches Problem, int könnte zu klein sein. Nimm std::size_t, das ist 
immer genau groß genug um Container zu iterieren.
1
catch(exception& e){
2
    cerr << "error: " << e.what() << endl;
3
}
Fehlerbehandlung ist zwar löblich, aber in so einem einfachen Programm 
nicht besonders sinnvoll, da hier ohnehin nur std::bad_alloc (Speicher 
voll) auftreten kann. Da man darauf sowieso kaum sinnvoll reagieren kann 
(die Ausgabe wird dann vermutlich abstürzen), kann man das auch gleich 
lassen.

Dein Code ist eh viel zu kompliziert, so gehts einfacher:
1
#include <iostream>
2
#include <algorithm>
3
#include <vector>
4
#include <string>
5
#include <cstddef>
6

7
int main () {
8
  std::vector<std::string> a { "Hallo", "das", "ist", "ein", "Testprogramm" };
9
  std::vector<std::size_t> b (a.size ());
10
  std::transform (a.begin (), a.end (), b.begin (), std::size<std::string>);
11
  
12
  std::size_t iShortest = std::min_element (b.begin (), b.end ()) - b.begin ();
13
  std::size_t iLongest = std::max_element (b.begin (), b.end ()) - b.begin ();
14
  
15
  std::size_t iLexFirst = std::min_element (a.begin (), a.end ()) - a.begin ();
16
  std::size_t iLexLast = std::max_element (a.begin (), a.end ()) - a.begin ();
17
  
18
  std::cout << "Shortest String: " << iShortest << " (\"" << a[iShortest] << "\")\nLongest String:  " << iLongest << " (\"" << a[iLongest] << "\")" << std::endl;
19
  std::cout << "Lex. First: " << iLexFirst << " (\"" << a[iLexFirst] << "\")\nLex. Last:  " << iLexLast << " (\"" << a[iLexLast] << "\")" << std::endl;
20
}
Gast #5298028
Lesenswert?

balankoff schrieb:
> Es gab ja keine Warnungen oder Fehler vom Compiler, das ist es ja eben.
> Normalerweise meldet er jede KLeinigkeit.

Da ist anscheinend etwas falsch konfiguriert. Selbst der MS-Compiler 
gibt mehrere Warnungen und einen Fehler aus:

Warnung  C4018 "<": Konflikt zwischen "signed" und "unsigned" x.cpp 25

Warnung  C4365 "Argument": Konvertierung von "int" in "const unsigned 
int", signed/unsigned-Konflikt. x.cpp 27

Warnung  C4365 "Argument": Konvertierung von "unsigned int" in "int", 
signed/unsigned-Konflikt. x.cpp 27

Fehler C4716 "getProps": Muss einen Wert zurückgeben x.cpp 43
Gast #5298196
Lesenswert?

Dr. Sommer schrieb:
> Dein Code ist eh viel zu kompliziert, so gehts einfacher

Danke, und deiner ist grauselich zu lesen :) Für mich ist er viel 
schwerer verständlich, aber gut ich bin noch nicht weit fortgeschritten 
was C++ angeht.

Oliver S. schrieb:
> Ansosnten als Tipp: Du solltes die Referenz-Parameter konstant machen

Stimmt, so ist sichergestellt, dass der Vektor nicht versehentlich 
verändert werden kann.
Gast #5298209
Lesenswert?

balankoff schrieb:
> Danke, und deiner ist grauselich zu lesen :)
Na, du musst nur die Dokumentation der Funktionen der 
Standard-Bibliothek lesen, dann wirds ziemlich klar... Dafür muss man 
sich nicht mit den Details der Algorithmen beschäftigen. Man muss 
lediglich wissen, wie Iteratoren funktionieren.
Gast #5298222
Lesenswert?

Dr. Sommer schrieb:
> (b.begin ()

Nach welchem Styleguide macht man zwischen dem Methodennamen und der 
Parameterklammer ein Blank?
Das sieht (zumindest für mich) ziemlich schräg aus.
1
Dr. Sommer schrieb im Beitrag #5298011:
2
> std::transform (a.begin (), a.end (), b.begin (), 
3
> std::size<std::string>);
4
> 
5
>   std::size_t iShortest = std::min_element (b.begin (), b.end ()) - 
6
> b.begin ();
7
>   std::size_t iLongest = std::max_element (b.begin (), b.end ()) - 
8
> b.begin ();
9
> 
10
>   std::size_t iLexFirst = std::min_element (a.begin (), a.end ()) - 
11
> a.begin ();
12
>   std::size_t iLexLast = std::max_element (a.begin (), a.end ()) - 
13
> a.begin ();
Das sind doch 5 Iterationen über den Vektor, wo eigentlich eine für die 
Aufgabe genügen würde.
Nenn mich altmodisch, aber mir gefällt sowas nicht.
Gast #5298229
Lesenswert?

Der Andere schrieb:
> Nach welchem Styleguide macht man zwischen dem Methodennamen und der
> Parameterklammer ein Blank?
In meinem.

Der Andere schrieb:
> Nenn mich altmodisch, aber mir gefällt sowas nicht.
Fertige Algorithmen (noch dazu solche aus der Standard-Bibliothek) 
machen den Code einfacher und vermeiden Bugs. Sollte der Code 
tatsächlich zu langsam sein und ein Profiling ergeben dass der 
Overhead durch die Schleifenzähler schuld ist, kann man das immer noch 
ändern. Lesbarkeit geht immer vor Effizienz, es sei denn man hat die 
Effizienz gemessen und für zu gering für die Anwendung befunden.
#5298333
Lesenswert?

return vector sollte man meiden, arbeite besser mit Referenzen, zudem 
solltest du dich an const correctness halten. Daher ist die 
Aufgabenstellung meiner Meinung nach eher als gaga zu betrachten.

Für die Algos ist ein Blick in die Standardbibliothek bzw. <algorithm> 
empfehlenswert, std::sort kann so einiges und arbeitet dabei relativ 
effizient.

Ich empfehle folgende Paramter für g++:

-std=c++11 -O2 -g  -Werror  -Wall -fmax-errors=1 -Wundef -Wextra 
-Wshadow -Wconversion -Wsign-promo -Wunused -Wsign-compare 
-Wstrict-aliasing
Gast #5298793
Lesenswert?

Sheeva P. schrieb:
> Egon N. schrieb:
> return vector sollte man meiden,
>
> Würdest Du wohl bitte aufhören, Anfängern Unfug zu erzählen? Danke.

Was soll daran falsch sein?

Der Compiler kann diese unnötigen Kopien nicht immer entfernen, sprich 
es ist deiner Meinung nach besser, bei einem 2GB großem Vector diesen zu 
kopieren statt mit diesem direkt zu arbeiten?

Und sich dann wundern, wieso der RAM nicht ausreicht...

Klar, wer nur mit Hello World und Objekten im kB Bereich hantiert wird 
sowas gerne machen, ich schreibe hingegen Anwendungen, die nur durch den 
Hauptspeicher begrenzt sind, da ist dann eine einzige Zahl so groß, dass 
sie teils mehr als die Hälfte des RAM verbraucht. Aber wenn du sagst, 
dass es besser ist, davon eine Kopie anzulegen, dann nur zu, kauf Mal 
einen Rechner mit mehr als 2TB RAM...
#5299138
Lesenswert?

Hans schrieb:
> Sheeva P. schrieb:
>> Egon N. schrieb:
>> return vector sollte man meiden,
>>
>> Würdest Du wohl bitte aufhören, Anfängern Unfug zu erzählen? Danke.
>
> Was soll daran falsch sein?
>
> Der Compiler kann diese unnötigen Kopien nicht immer entfernen, sprich
> es ist deiner Meinung nach besser, bei einem 2GB großem Vector diesen zu
> kopieren statt mit diesem direkt zu arbeiten?

Der Compiler muss das im aktuellen Sprachstandard sogar machen an der 
Stelle, und mit verschiebbaren Objekten hat das auch nix zu tun. Das 
passiert garantiert immer, egal ob das Objekt einen Move-Konstruktor hat 
oder nicht.
Gast #5299163
Lesenswert?

Dr. Sommer schrieb:
> Fertige Algorithmen (noch dazu solche aus der Standard-Bibliothek)
> machen den Code einfacher und vermeiden Bugs.

Das ist völlig richtig. Aber blind danach verfahren kann auch daneben 
sein.

1. Wenn der Vektor sehr groß sein sollte macht sich das massiv bemerkbar 
ob ich da einmal oder 5mal durchiteriere nur um solche trivialen Dinge 
wie ein Maximum oder Minimum zu finden.
2. Ich habe hier in meiner Firma schon erlebt (Java Umfeld) daß jemand 
extra aus ausschliesslich eine Google Lib mit eingebunden hat nur um ein 
Close einer Datenbankverbindung nicht selbst (incl ein try .. catch) zu 
schreiben und das genau mit der Aussage "use standard and tested code if 
possible" begründet hat.
3. Das ist ein Übungsbeispiel. Man kann also durchaus vermuten daß der 
TO vieleicht lernen soll wie man ein Maximum oder ein Minimum selber 
programmiert.

Man wird heutzutage zugeschissen mit Libs und fertigem Code. Das sollte 
einem aber nicht davon abhalten selber noch ein bischen nachzudenken.
#5299432
Lesenswert?

Dr. Sommer schrieb:
> Dein Code ist eh viel zu kompliziert, so gehts einfacher:

Allerdings sollte man dann doch drauf hinweisen, daß das noch etwa auf 
der "bleedind edge" der Sprachdefinition reitet. std::size gibts erst ab 
C++17,

und der gerade erst bei mir angekommene gcc 7.3.0 sagt dazu:
1
g++ -std=c++1z -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\test.o" "..\\src\\test.cpp" 
2
..\src\test.cpp: In function 'int main()':
3
..\src\test.cpp:10:75: internal compiler error: in type_throw_all_p, at cp/except.c:1186
4
   std::transform (a.begin (), a.end (), b.begin (), std::size<std::string>);
5
                                                                           ^
6
libbacktrace could not find executable to open
7
Please submit a full bug report,
8
with preprocessed source if appropriate.
9
See <https://sourceforge.net/projects/msys2> for instructions

Oliver
Gast #5299596
Lesenswert?

Oliver S. schrieb:
> und der gerade erst bei mir angekommene gcc 7.3.0 sagt dazu:
Na sowas, mit GCC 7.2.1, 7.2, 7.1 und Clang 4.0.0 gehts. Die fragliche 
Stelle benutzt gar kein brandneues C++17-Sprachfeature, lediglich 
std::size ist neu aber nur eine gewöhnliche Funktion.

Kartoffelbovistverwandter schrieb:
> Tipp: minmax_element (gegebenfalls mit Lambda) und tie; ist kürzer und
> man muss zumindest nicht 4x drüber.
Auch nett, aber so sieht's so imperativ und nicht-funktional aus... ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren