|
| Crash, men hvor? Fra : Mads A. Jensen |
Dato : 19-05-02 21:02 |
|
Hej
Jeg er ny til c++. Når jeg afvikler følgende kode, kommer der en fejl, men
hvad skyldtes fejlen:
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <iostream.h>
#include <fstream.h>
int main(int argc, char *argv[])
{
char *line;
char *file;
int *i;
if(argv[1] == NULL){
cout << "Location of file: ";
cin >> file;
}
else{
file = argv[1];
}
ifstream filep(file);
while(!filep.eof()){
filep.getline(line, sizeof(line));
i = (i + 1);
}
cout << "Number of lines in file were: " << i << endl;
return 0;
}
Det skal lige siges, at jeg bruger MinGw og Dev C++ 4. På en Windows 2000
maskine!
Mange tak for hjælpen.
/Mads
--
--
Mads Jensen
http://ddfr.dk - Dansk Donaldist Forening
http://www.disney-comics.dk - Free Disney comics on the web!
info@disney-comics.dk
| |
Anders Borum (19-05-2002)
| Kommentar Fra : Anders Borum |
Dato : 19-05-02 21:34 |
|
"Mads A. Jensen" <mads@NOSPAManything.dk> skrev i en meddelelse
news:ac906c$8pj$1@sunsite.dk...
> Hej
>
> Jeg er ny til c++. Når jeg afvikler følgende kode, kommer der en fejl, men
> hvad skyldtes fejlen:
Hej Mads
Dit eksempel indeholder flere mulige årsager til fejlen.
[klip]
> int main(int argc, char *argv[])
> {
> char *line;
> char *file;
> int *i;
> if(argv[1] == NULL){
Hvis programmet kaldes uden argumenter er argv[1] ikke
veldefineret. Når du sammenligner det med NULL kan du
risikere en fejl.
I stedet for at checke om argv[1] == NULL skulle du
hellere undersøge om argc (argument count) er stor nok.
> cout << "Location of file: ";
> cin >> file;
Du indlæser her en linie fra terminalen og placerer den
i hukommelsen som file-variablen peger på. Men file peger
ikke nogen steder hen og så vil et eller andet gå galt.
Du kunne erklære file som en array:
char file[80];
Men det kan stadig gå galt hvis der bliver indtastet for mange
tegn på terminalen.
> }
> else{
> file = argv[1];
> }
>
> ifstream filep(file);
>
> while(!filep.eof()){
> filep.getline(line, sizeof(line));
Her gentager problemet sig med line.
> i = (i + 1);
> }
> cout << "Number of lines in file were: " << i << endl;
> return 0;
> }
[klip]
| |
Anders Melchiorsen (19-05-2002)
| Kommentar Fra : Anders Melchiorsen |
Dato : 19-05-02 21:48 |
|
"Anders Borum" <overflade@fedt.dk> skrev:
> Hvis programmet kaldes uden argumenter er argv[1] ikke veldefineret.
Hm, argv[] er nulafsluttet, såfremt argc > 0.
Strengt taget har du ret, men præmissen er "argc==0", ikke "programmet
kaldes uden argumenter".
> Du kunne erklære file som en array:
> char file[80];
Et bedre valg er nok
std::string file;
Anders.
--
Address is valid for a week.
After that, remove (only) the '.day-JJJ-YYYY' part.
| |
Ivan Johansen (19-05-2002)
| Kommentar Fra : Ivan Johansen |
Dato : 19-05-02 21:51 |
|
Anders Melchiorsen wrote:
> "Anders Borum" <overflade@fedt.dk> skrev:
> Strengt taget har du ret, men præmissen er "argc==0", ikke "programmet
> kaldes uden argumenter".
Er det muligt? Indeholder argv[0] ikke altid filnavnet?
Ivan Johansen
| |
Anders Melchiorsen (19-05-2002)
| Kommentar Fra : Anders Melchiorsen |
Dato : 19-05-02 23:35 |
|
Ivan Johansen <NG@Padowan.dk> skrev den 19-May-02:
> Anders Melchiorsen wrote:
>
> > "Anders Borum" <overflade@fedt.dk> skrev:
> > Strengt taget har du ret, men præmissen er "argc==0", ikke "programmet
> > kaldes uden argumenter".
>
>
> Er det muligt? Indeholder argv[0] ikke altid filnavnet?
Ikke hvis argc er lig nul.
I øvrigt kan argv[0][0] også være nul, selv hvis argc>0.
Anders.
--
Address is valid for a week.
After that, remove (only) the '.day-JJJ-YYYY' part.
| |
Ivan Johansen (20-05-2002)
| Kommentar Fra : Ivan Johansen |
Dato : 20-05-02 00:01 |
|
Anders Melchiorsen wrote:
> Ikke hvis argc er lig nul.
>
> I øvrigt kan argv[0][0] også være nul, selv hvis argc>0.
Men kan argc være 0? Så har programmet ikke noget filnavn. Er det muligt?
Ivan Johansen
| |
Byrial Jensen (20-05-2002)
| Kommentar Fra : Byrial Jensen |
Dato : 20-05-02 08:36 |
|
Ivan Johansen <NG@Padowan.dk> skrev:
> Anders Melchiorsen wrote:
>
>> Ikke hvis argc er lig nul.
>>
>> I øvrigt kan argv[0][0] også være nul, selv hvis argc>0.
>
> Men kan argc være 0? Så har programmet ikke noget filnavn. Er det muligt?
Nu var der tale om et C++-program, og der kender jeg ikke reglerne,
men i et C-program må argc gerne være 0, og hvis argc er større end
0, må argv[0] gerne være en tom streng.
| |
Mogens Hansen (20-05-2002)
| Kommentar Fra : Mogens Hansen |
Dato : 20-05-02 09:24 |
|
"Anders Melchiorsen" <postmaster@anders.day-139-2002.nospam.kalibalik.dk>
wrote
>
> Hm, argv[] er nulafsluttet, såfremt argc > 0.
>
Kravet er at argv[argc] er 0, og at argc ikke er negativ.
Altså argc må gerne være 0, og også i det tilfælde vil argv[argc] være 0.
Venlig hilsen
Mogens Hansen
| |
Anders Borum (20-05-2002)
| Kommentar Fra : Anders Borum |
Dato : 20-05-02 10:19 |
|
"Anders Melchiorsen" <postmaster@anders.day-139-2002.nospam.kalibalik.dk>
skrev i en meddelelse news:m2offb7tkk.fsf@dolle.kalibalik.dk...
> "Anders Borum" <overflade@fedt.dk> skrev:
>
> > Hvis programmet kaldes uden argumenter er argv[1] ikke veldefineret.
>
> Hm, argv[] er nulafsluttet, såfremt argc > 0.
>
> Strengt taget har du ret, men præmissen er "argc==0", ikke "programmet
> kaldes uden argumenter".
Nu hvor jeg kigger efter er der i "K&R's CPL 2. udg." eksempler hvor det
antages at argc != 0; fx. side 163. Så måske præmissen slet ikke er
nødvendig.
> > Du kunne erklære file som en array:
> > char file[80];
>
> Et bedre valg er nok
>
> std::string file;
Ja - det er det nok.
De iostreams der følger med min egen Visual C++ version 6 kan ikke
indlæse direkte til en std::string og cin har altså ikke mulighed for
at øge kapaciteten for file-objektet hvis det skulle blive nødvendigt.
Jeg tror jeg skifter til gcc.
Anders
| |
Byrial Jensen (20-05-2002)
| Kommentar Fra : Byrial Jensen |
Dato : 20-05-02 11:21 |
|
Anders Borum <overflade@fedt.dk> skrev:
> Nu hvor jeg kigger efter er der i "K&R's CPL 2. udg." eksempler hvor det
> antages at argc != 0; fx. side 163.
Ja, K&R2 siger at argc er mindst 1 (øverst s. 115), og laver
eksempler der bygger på den antagelse. Den holder bare ikke for C99
(se afsnit 5.1.2.2.1), og ifølge Mogens Hansen heller ikke for C++.
Jeg kan ikke huske hvad ANSI C siger om det.
> Så måske præmissen slet ikke er
> nødvendig.
Jo.
| |
Anders Borum (20-05-2002)
| Kommentar Fra : Anders Borum |
Dato : 20-05-02 12:23 |
|
"Byrial Jensen" <bjensen@nospam.dk> skrev i en meddelelse
news:slrnaehjhj.28f.bjensen@ask.ask...
> Anders Borum <overflade@fedt.dk> skrev:
> > Nu hvor jeg kigger efter er der i "K&R's CPL 2. udg." eksempler hvor det
> > antages at argc != 0; fx. side 163.
>
> Ja, K&R2 siger at argc er mindst 1 (øverst s. 115), og laver
> eksempler der bygger på den antagelse. Den holder bare ikke for C99
> (se afsnit 5.1.2.2.1), og ifølge Mogens Hansen heller ikke for C++.
>
> Jeg kan ikke huske hvad ANSI C siger om det.
Her er hvad en ISO draft fra 3. august 1998 siger.
Den færdige ANSI standard koster penge, så den kan jeg ikke citere.
5.1.2.2.1 Program startup
[#1] The function called at program startup is named main.
The implementation declares no prototype for this function.
It shall be defined with a return type of int and with no
parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv,
though any names may be used, as they are local to the
function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;8) or in some other implementation-defined
manner.
[#2] If they are declared, the parameters to the main
function shall obey the following constraints:
-- The value of argc shall be nonnegative.
-- argv[argc] shall be a null pointer.
-- If the value of argc is greater than zero, the array
members argv[0] through argv[argc-1] inclusive shall
contain pointers to strings, which are given
implementation-defined values by the host environment
prior to program startup. The intent is to supply to
____________________
8) Thus, int can be replaced by a typedef name defined as
int, or the type of argv can be written as char ** argv,
and so on.
5.1.2 Environment 5.1.2.2.1
12 Committee Draft -- August 3, 1998 WG14/N843
the program information determined prior to program
startup from elsewhere in the hosted environment. If
the host environment is not capable of supplying
strings with letters in both uppercase and lowercase,
the implementation shall ensure that the strings are
received in lowercase.
-- If the value of argc is greater than zero, the string
pointed to by argv[0] represents the program name;
argv[0][0] shall be the null character if the program
name is not available from the host environment. If
the value of argc is greater than one, the strings
pointed to by argv[1] through argv[argc-1] represent
the program parameters.
-- The parameters argc and argv and the strings pointed to
by the argv array shall be modifiable by the program,
and retain their last-stored values between program
startup and program termination.
> > Så måske præmissen slet ikke er
> > nødvendig.
>
> Jo.
| |
Byrial Jensen (20-05-2002)
| Kommentar Fra : Byrial Jensen |
Dato : 20-05-02 14:47 |
|
Anders Borum <overflade@fedt.dk> skrev:
> "Byrial Jensen" <bjensen@nospam.dk> skrev i en meddelelse
> news:slrnaehjhj.28f.bjensen@ask.ask...
>> Anders Borum <overflade@fedt.dk> skrev:
>> > Nu hvor jeg kigger efter er der i "K&R's CPL 2. udg." eksempler hvor det
>> > antages at argc != 0; fx. side 163.
>>
>> Ja, K&R2 siger at argc er mindst 1 (øverst s. 115), og laver
>> eksempler der bygger på den antagelse. Den holder bare ikke for C99
>> (se afsnit 5.1.2.2.1), og ifølge Mogens Hansen heller ikke for C++.
>>
>> Jeg kan ikke huske hvad ANSI C siger om det.
>
> Her er hvad en ISO draft fra 3. august 1998 siger.
Det du citerer fra, må være et udkast til C99-standarden (ISO/IEC
9899:1999).
Med ANSI C menes den standard som først blev vedtaget af ANSI i
1989, og siden af ISO og IEC året efter som ISO/IEC 9899:1990, og
som nu teknisk set er forældet idet den er afløst af C99.
Jeg er som sagt ikke sikker på hvad ANSI C siger om argc, men jeg
formoder at værdien 0 også tillades her.
| |
Richard Flamsholt (22-05-2002)
| Kommentar Fra : Richard Flamsholt |
Dato : 22-05-02 00:53 |
|
Byrial Jensen <bjensen@nospam.dk> skrev:
>Jeg er som sagt ikke sikker på hvad ANSI C siger om argc, men jeg
>formoder at værdien 0 også tillades her.
Det gør C89, ja: 5.1.2.2.1. Der står bl.a., at hvis argc>0 repræsenterer
argv[0] programnavnet og at argv[0][0] er nul såfremt navnet ikke findes
der, hvor main() kaldes fra. Det kan fx være via en exec*() som ikke kan
eller vil aflevere programnavnet i argv[0].
Iøvrigt læste jeg det her i Schildt's annoterede udgave af C-standarden
(skønt jeg faktisk har den rigtige på papir, men den var længere væk) og
på højresiden brillerer han med at konkludere, at eftersom main ikke har
en prototype kan man definere den som man har lyst til (ja, det skriver
han faktisk!), fx som "void main(void)".
Endnu et glimrende argument for at hive alle højresiderne ud af den bog,
og såmænd nok også alle hans andre bøger...
--
Richard Flamsholt
richard@flamsholt.dk - www.richard.flamsholt.dk
| |
Claus Rasmussen (19-05-2002)
| Kommentar Fra : Claus Rasmussen |
Dato : 19-05-02 21:39 |
|
Mads A. Jensen wrote:
> Jeg er ny til c++. Når jeg afvikler følgende kode, kommer der en fejl, men
> hvad skyldtes fejlen:
[...]
> filep.getline(line, sizeof(line));
'line' skal være allokeret på forhånd. Og når du bruger sizeof() på
en pointer, får du kun størrelsen på pointeren - ikke størrelsen af
det, den peger på.
Du kan prøve med flg. lille test:
int main() {
char* line1;
char line2[80+1];
cout << sizeof(line1) << endl
<< sizeof(line2) << endl;
}
MVH
-Claus
| |
Ivan Johansen (19-05-2002)
| Kommentar Fra : Ivan Johansen |
Dato : 19-05-02 21:50 |
|
Mads A. Jensen wrote:
> Jeg er ny til c++. Når jeg afvikler følgende kode, kommer der en
fejl, men
> hvad skyldtes fejlen:
Hvis du skrev hvad fejlen bestod i og helst hvor fejlen opstår ville det
hjælpe en hel del. Kan programmet ikke compiles eller springer
computeren i luften, når programmet køres?
> #include <stdio.h>
> #include <math.h>
> #include <string.h>
Disse bør ændres til <cstdio>, <cmath> og <cstring>. <stdio.h>, <math.h>
og <string.h> er kun understøttet af hensyn til bagudkompatibilitet og
bør derfor ikke bruges i ny kode.
> #include <iostream.h>
> #include <fstream.h>
Disse findes ikke i standarden. De hedder <iostream> og <fstream>. Du
skal desuden skrives
using namespace std;
hvis du ikke vil skrive std:: foran alt i namespace std.
> int main(int argc, char *argv[])
> {
> char *line;
> char *file;
> int *i;
Da jeg kan se at du bruger i til at tælle linier med skal den ikke være
en pointer brug følgende i steret:
int i;
> if(argv[1] == NULL){
> cout << "Location of file: ";
> cin >> file;
Her overskriver du et tilfældigt sted i hukommelsen. Jeg vil anbefale at
du erklærer file som:
string file;
og åbner filen med:
ifstream filep(file.c_str());
> }
> else{
> file = argv[1];
> }
> ifstream filep(file);
Du undersøger ikke om det lykkedes at åbne filen:
if(!filep)
{
cerr << "Could not open file"
return 1;
}
> while(!filep.eof()){
> filep.getline(line, sizeof(line));
Her læser du en linie ind hvor line peger. Da du ikke har allokeret
hukommelse til line, vil du overskrive data et tilfældigt sted i
hukommelsen. Du læser højest 4 bytes, da dette er størrelsen på en
pointer under Windows 2000.
Du kan løse problemet ved at deklarere line som:
char line[100];
Dette afsætter 100 bytes til din linie inklusiv terminering. Da line nu
er et array i stedet for en pointer, vil sizeof(line) korrekt returnere
størrelsen på dit array i stedet for størrelsen på en pointer.
En endnu bedre løsning ville være at bruge en std::string.
string line;
while(!filep.eof()){
getline(filep, line);
Her behøver du ikke tænker på hvor stor en linie kan være. line får
automatisk den størrelse, som er nødvendig. Husk dog
#include <string>
> i = (i + 1);
Dette skrives normalt i c++ som
++i;
Jeg håber at du kan bruge mine kommentarer.
Ivan Johansen
| |
Igor V. Rafienko (21-05-2002)
| Kommentar Fra : Igor V. Rafienko |
Dato : 21-05-02 13:09 |
|
[ Ivan Johansen ]
> > while(!filep.eof()){
> > filep.getline(line, sizeof(line));
[ snip ]
> En endnu bedre løsning ville være at bruge en std::string.
> string line;
>
> while(!filep.eof()){
> getline(filep, line);
>
> Her behøver du ikke tænker på hvor stor en linie kan være. line får
> automatisk den størrelse, som er nødvendig. Husk dog
> #include <string>
Nesten. Bortsett fra den situasjonen når:
* man leser den siste linjen MEN eofbit ikke blir satt (det er en
mulig hendelsesforløp). Antall linjer økes med 1.
* Man tester på eofbif, som ikke er satt enda og går inn i løkken. Der
gjør man en getline som forsøker å lese forbi EOF, noe som
naturligvis går galt. Når blir (bl.a.) eofbit satt
* Og man øker antall linjer med 1 for en ikke-eksisterende linje.
Svaret blir 1 linje for mye.
En av riktige varianter er:
while ( getline( filep, line ) )
++count;
der man tester på streamstate _før_ man kommer inn i løkken. En ganske
så vesentlig forskjell.
ivr, som har sans for Mogens sitt forslag
--
C++: "an octopus made by nailing extra legs onto a dog"
-- Steve Taylor, 1998
| |
Ivan Johansen (21-05-2002)
| Kommentar Fra : Ivan Johansen |
Dato : 21-05-02 21:21 |
|
Igor V. Rafienko wrote:
> Nesten. Bortsett fra den situasjonen når:
>
> * man leser den siste linjen MEN eofbit ikke blir satt (det er en
> mulig hendelsesforløp). Antall linjer økes med 1.
> * Man tester på eofbif, som ikke er satt enda og går inn i løkken. Der
> gjør man en getline som forsøker å lese forbi EOF, noe som
> naturligvis går galt. Når blir (bl.a.) eofbit satt
> * Og man øker antall linjer med 1 for en ikke-eksisterende linje.
>
> Svaret blir 1 linje for mye.
Selvfølgelig. Det havde jeg lige overset.
> En av riktige varianter er:
>
> while ( getline( filep, line ) )
> ++count;
Det ser flot ud. Det vil jeg lige huske på.
Ivan Johansen
| |
Jesper Toft (19-05-2002)
| Kommentar Fra : Jesper Toft |
Dato : 19-05-02 21:52 |
|
Mads A. Jensen wrote:
Du benytter pointere men allokere ikke hukommelse til dem ikke..
> char *line;
Denne bør være:
char line[1000];
> char *file;
> int *i;
Denne bør være:
int i = 0;
> if(argv[1] == NULL){
> cout << "Location of file: ";
indsæt noget i retningen af:
file = new char[1000];
> cin >> file;
> }
/Jesper
| |
Mogens Hansen (20-05-2002)
| Kommentar Fra : Mogens Hansen |
Dato : 20-05-02 09:28 |
|
"Mads A. Jensen" <mads@NOSPAManything.dk> wrote
fra de andre svar, ved du at et væsentligt problemer er at du ikke har
allokeret plads
> Jeg er ny til c++. Når jeg afvikler følgende kode, kommer der en fejl, men
> hvad skyldtes fejlen:
>
> #include <stdio.h>
> #include <math.h>
> #include <string.h>
Hvorfor includerer du stdio, math og string ?
Så vidt jeg kan se, bruger du dem ikke.
[snip]
> int main(int argc, char *argv[])
> {
> char *line;
> char *file;
Generelt er det en god ide, i C++, at vente med at erklære variable til man
har brug for dem.
[snip]
> ifstream filep(file);
>
Hvad hvis filen ikke kan åbnes ?
> while(!filep.eof()){
Det bør nok nærmere være
while(filep) {
Du kan gøre programmet mere tydeligt, og sikkert ved at sige:
"jeg skal lave et program, der kan tælle antallet af linier i en fil",
og bruge standard algoritmen std::count
#include <fstream>
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
#include <cstdlib>
int main(int argc, char *argv[])
{
using namespace std;
string file_name;
if(2 != argc) {
cout << "Location of file:" << endl;
getline(cin, file_name);
}
else {
file_name = argv[1];
}
ifstream is(file_name.c_str(), ios_base::binary);
if(!is) {
cerr << "Unable to upen file: " << file_name << endl;
return EXIT_FAILURE;
}
cout << "Number of lines in file were: "
<< count(
istreambuf_iterator<char>(is),
istreambuf_iterator<char>(),
'\n')
<< endl;
}
Metoden kan bruges uanset om det er antallet af linieskift eller antallet af
et andet tegn der skal skrives.
Venlig hilsen
Mogens Hansen
| |
|
|