Avatar billede Slettet bruger
30. august 2008 - 13:23 Der er 14 kommentarer og
1 løsning

Begynderproblemer - og ingen fejlmelding

Hej eksperter,

Først vil jeg lige sige, at jeg er absolut C++-begynder, men at jeg tidligere har skrevet andre programmeringssprog (C#, Java, ActionScript...).
Og nu til problemet: Jeg får tre fejl i denstående kode.

#include <string>
#include <math.h>

public static class Alias
{
public:
    static string Encrypt (string subject, string codex)
    {
        if (subject.length == 0 || codex.length == 0)
            return null;
        long addition = 0;
        string result ("");
        for (long i = 0; i < codex.length; i++)
            addition += (pow (2, i) - 1) * 256 + codex[i];
        for (long i = 0; i < subject.length; i++)
            result += (subject[i] + addition + codex[i % (codex.length - 1)]) % 255;
        return result;
    }
}

Det er et enkelt script til en krypteringsmotor. Hovedproblemet er nu, at jeg ikke kan se fejlene i Error-rammen. Hvorfor ikke? Desuden tror jeg, at selve de tre kodefejl skyldes problemer med type casting - ved omregning fra char til karakterkode (0-255). Hvordan løser jeg problemerne?

Det var to spørgsmål, jeg håber, I kan besvare.
Avatar billede mbulow Nybegynder
30. august 2008 - 16:19 #1
Jeg tager lige tingene, en ad gangen...


1) "public static" foran class-definitionen bruges ikke i C++. (Jeg vil gætte på at det er noget du har "arvet" fra Java :) )


2) string er en del af STL (Standard Template Library) og er defineret i namespacet std. Der skal derfor skrives std::string.

Evt kan du vælge at skrive: "using namespace std;" før du bruger namespacet. Så er du fri for altid at skrive "std::"


3) string::length er en funktion. Husk derfor ()


4) null findes ikke i C++. Brug istedet værdien 0.


5) pow i C++ arbejder med kommatal (dvs. float, double eller long double). Da dit behov er et simpelt spørgsmål om at opløfte 2 til i'te potens er følgende lettere end at caste argumenterne:

    (1 << i)

    Bemærk: Du har ikke længere brug for at inkludere math.h


6) En class definition sluttes af med et ;

----------

#include <string>

class Alias
{
public:
    static std::string Encrypt (std::string subject, std::string codex)
    {
        if (subject.length() == 0 || codex.length() == 0)
            return 0;
        long addition = 0;
        std::string result ("");
        for (long i = 0; i < codex.length(); i++)
            addition += ((1 << i) - 1) * 256 + codex[i];
        for (long i = 0; i < subject.length(); i++)
            result += (subject[i] + addition + codex[i % (codex.length() - 1)]) % 255;
        return result;
    }
};

----------

Nu compilerer klassen, men du vil få nogle warnings:

1) I dine for-loops er 'i' af typen 'long' (med fortegn). string::length() returnerer en værdi uden fortegn. Det er det du bliver advaret om i forbindelse med din '<' sammenligning.
Du kan f.eks. skifte 'long' ud med 'std::string::size_type'.
Så er du sikker på at 'i' er af samme type som string::length() returnerer.

2) Linien med 'result += (sub...1)]) % 255;'
Her er højresiden af typen 'long', men 'result +=' forventer at det er en 'char'.
Cast derfor højresiden til en 'char', for at slippe for advarslen.
result += static_cast<char>((subject[i] + addition + codex[i % (codex.length() - 1)]) % 255);

----------

#include <string>

class Alias
{
public:
    static std::string Encrypt (std::string subject, std::string codex)
    {
        if (subject.length() == 0 || codex.length() == 0)
            return 0;
        long addition = 0;
        std::string result ("");
        for (std::string::size_type i = 0; i < codex.length(); i++)
            addition += ((1 << i) - 1) * 256 + codex[i];
        for (std::string::size_type i = 0; i < subject.length(); i++)
            result += static_cast<char>((subject[i] + addition + codex[i % (codex.length() - 1)]) % 255);
        return result;
    }
};
Avatar billede Slettet bruger
30. august 2008 - 16:47 #2
1) Det har jeg fra C# - i Java kan klasser være public/private/protected med ikke static. Ellers et godt bud :)

2) Ups!

3) Begynderfejl... Igen et levn fra C# (der ofte benytter egenskaber frem for metoder).

4) Ok. Kan jeg bruge værdien 0 til en string?

5) Forklaring søges!

6) Igen en begynderfejl med rod i de andre sprog, jeg skriver.

Jeg retter lige ovenstående fejl og skriver igen.
Avatar billede Slettet bruger
30. august 2008 - 17:01 #3
Okay. Nu ser mine filer således ud:

--- Encryption.cpp ---

#include "stdafx.h"
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    cout << Alias::Encrypt("SuBjEcT", "CoDeX");
    cin.get();
    return 0;
}


--- Alias.cpp ---

#include <string>
#include <cmath>

using namespace std;

class Alias
{
public:
    static string Encrypt(string subject, string codex)
    {
        if (subject.length() == 0 || codex.length() == 0)
            return 0;
        long addition = 0;
        string result("");
        for (string::size_type i = 0; i < codex.length(); i++)
            addition += long((pow(double(2), double(i)) - 1) * 256 + codex[i]);
        for (string::size_type i = 0; i < subject.length(); i++)
            result += (subject[i] + addition + codex[i % (codex.length() - 1)]) % 255;
        return result;
    }
};


Jeg får følgende fejl (jeg har nu opdaget, at fejlene, i modsætning til dem C#-compileren finder, står i Output-rammen og ikke Error List-rammen):

1>------ Build started: Project: Encryption, Configuration: Debug Win32 ------
1>Compiling...
1>Alias.cpp
1>Encryption.cpp
1>encryption.cpp(8) : error C2653: 'Alias' : is not a class or namespace name
1>encryption.cpp(8) : error C3861: 'Encrypt': identifier not found
1>Generating Code...
1>Build log was saved at "file://Encryption\Encryption\Debug\BuildLog.htm"
1>Encryption - 2 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


PS: Jeg søger stadig svar på spørgsmålene stillet i ovenstående kommentar.
Avatar billede mbulow Nybegynder
30. august 2008 - 19:02 #4
Spørgsmål:



3) Det kræver lidt forklaring... Det går ud på at jeg laver et implicit kald til en stringconstructor. Når du skriver 'return 0' i en funktion som skal returnere en string, prøver compileren at finde en string-constructor som kan modtage et 0, som sin eneste parameter. I princippet står der altså 'return string(0)'

F.eks. laver du lidt længere nede et explicit kald til en stringconstructor:
  string result("");
men det kunne lige så godt være lavet som et explicit kald:
  string result = "";

Her prøver compileren selv at finde en constructor der kan modtage "" som eneste parameter. Kan der ikke findes en brugbar constructor vil det give en fejl, hvilket det også vil hvis der findes flere forskellige constructore der kan håndtere kaldet.



5) Det her går ud på bitmanipulation.
<< og >> flytter bit'ne i en variabel til hhv. venstre og højre.

F.eks. kan tallet 4 repræsenteres binært som 00000100.
Skriver du f.eks. '4 << 2' kan du se det som '00000100 << 2'.

Resultatet er at bit'ne er flyttet to pladser til venstre. Altså: '00000100 << 2 == 00010000' (Sådan kan det ikke skrives i et program). Bemærk at '00010000' er den binære repræsentation af tallet 16.

Her nedenfor har jeg opstillet en lille tabel:
(Håber den statig står ordentlig når jeg sender svaret)

2^0      1    00000001    1 << 0
2^1      2    00000010    1 << 1
2^2      4    00000100    1 << 2
2^3      8    00001000    1 << 3
2^4      16    00010000    1 << 4
2^5      32    00100000    1 << 5
2^6      64    01000000    1 << 6
2^7    128    10000000    1 << 7

Fra venstre mod højre har jeg skrevet:
- En potens som du bruger dem med pow()
- Den faktiske værdi af potensen
- Den binære repræsentation af værdien
- Det samme tal repræsenteret som et 1-tal left-shifted et antal bit

Bemærk dog at denne simple sammenhænge mellem pow()-funktionen og left-shifting (<<) kun gælder så længe 'basen' i pow() er 2.

Har du brug for nærmere forklaring kan du prøve at google lidt efter det på google.
F.eks.: binary numbers programming
Avatar billede arne_v Ekspert
30. august 2008 - 19:03 #5
re 17:01:30>

Jeg tror at du skal have en Alias.h som kan inkluderes i Encryption.cpp
Avatar billede mbulow Nybegynder
30. august 2008 - 19:09 #6
Problemet med at du ikke kan kompilere din nye kode er at du skal inkludere "Alias.cpp" i "Encryption.cpp"

--- Encryption.cpp ---

#include "Alias.cpp"
#include "stdafx.h"
#include <iostream>
#include <tchar.h>  //Skal desuden huske den her for at kunne bruge _TCHAR

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    cout << Alias::Encrypt("SuBjEcT", "CoDeX");
    cin.get();
    return 0;
}


--- Alias.cpp ---

#include <string>
#include <cmath>

using namespace std;

class Alias
{
public:
    static string Encrypt(string subject, string codex)
    {
        if (subject.length() == 0 || codex.length() == 0)
            return 0;
        long addition = 0;
        string result("");
        for (string::size_type i = 0; i < codex.length(); i++)
            addition += long((pow(double(2), double(i)) - 1) * 256 + codex[i]);
        for (string::size_type i = 0; i < subject.length(); i++)
            result += (subject[i] + addition + codex[i % (codex.length() - 1)]) % 255;
        return result;
    }
};
Avatar billede mbulow Nybegynder
30. august 2008 - 19:15 #7
Ja, Arne har ret.

Egentlig virker det jeg lige har skrevet, men... Det vil give dig en væsentligt pænere struktur på din kode, hvis du sætter dig ind i hvordan du bruger header-files.

Jeg vil faktisk sige at det er nødvendigt når du når op i større projekter.
Avatar billede Slettet bruger
30. august 2008 - 20:18 #8
Mange tak for de gode svar :) Jeg læser lige lidt om headere og roder videre med koden.
Avatar billede Slettet bruger
30. august 2008 - 20:26 #9
Hov! Jeg tror, der er noget, en eller andet har overset - for #include "alias.h" virker ikke, mens #include "alias.cpp" fungerer:

#include "stdafx.h"
#include <iostream>
#include "alias.cpp"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    cout << Alias::Encrypt("SuBjEcT", "CoDeX");
    cin.get();
    return 0;
}

Ingen fejl ved ovenstående. Kan I forklare mig, hvorfor jeg skulle få en Alias.h (kildekoden er gemt som Alias.cpp), og hvorfor dette alligevel ike er, hvad jeg skal refferere til?
Avatar billede Slettet bruger
30. august 2008 - 20:42 #10
Jeg har nu rettet min main-metode til at hedde void main().

Desuden har jeg et rimelig off-topic spørgsmål - hvorfor melder følgende fejl:
cout <<
        "Subject: " << subject << "\nCodex: " << codex << "\nEncryption: " << encryption << "\nDecryption: " << decryption <<
        "\nDecrypted encryption: " << decryptedEncryption << "\nEncrypted decryption: " << encryptedDecryption <<
        "\nStatus: " << (decryptedEncryption == encryptedDecryption == subject ? "Succes" : "Failure") << ".";
Avatar billede mbulow Nybegynder
30. august 2008 - 21:02 #11
Det er rigtigt at: #include "Alias.h"
ikke fungerer som det ser ud lige nu.

Det går ud på at du (ihvertfald i større projekter) bør arbejde med både .cpp og .h filer, for at strukturere programmet bedre.

Lad os kalde .h filerne for header-filerne, og
.cpp filerne for source-filerne.

En ALT for simpel forklaring er at man beskriver programstrukturen i headerfilerne.
F.eks. en klassedefinition.

I sourcefilerne implementerer man selve funktionaliteten.
F.eks. en klasses funktioner.
Avatar billede mbulow Nybegynder
30. august 2008 - 21:12 #12
Hov... Den skulle ikke være sendt endnu :)

Lad mig vise dig hvordan jeg ville strukturere dit program i forskellige filer:



--- Encryption.cpp ---

//Den her fil ser sådan set ud som den hele tiden har gjort,
//lige ud over at jeg altså nu inkluderer Alias.h istedet Alias.cpp

#include "Alias.h"
#include "stdafx.h"
#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
    cout << Alias::Encrypt("SuBjEcT", "CoDeX");
    cin.get();
    return 0;
}



--- Alias.h ---

//Her i headerfilen beskriver jeg hvordan strukturen som omhandler
//Alias ser ud. Altså i dette tilfælde "blot" en klassedefinition.

#ifndef ALIAS_H__INCLUDED
#define ALIAS_H__INCLUDED

#include <string>

using namespace std;

class Alias
{
public:
    static string Encrypt(string subject, string codex);
};

#endif  //ALIAS_H__INCLUDED



--- Alias.cpp ---

//Her i sourcefilen implementerer jeg nu funktionaliteten som omhandler Alias.
//I det her tilfælde definerer jeg bare funktionerne som er deklareret i headerfilen
#include "Alias.h"
#include <string>
#include <cmath>

using namespace std;

string Alias::Encrypt(string subject, string codex)
{
    if (subject.length() == 0 || codex.length() == 0)
        return 0;
    long addition = 0;
    string result("");
    for (string::size_type i = 0; i < codex.length(); i++)
        addition += long((pow(double(2), double(i)) - 1) * 256 + codex[i]);
    for (string::size_type i = 0; i < subject.length(); i++)
        result += (subject[i] + addition + codex[i % (codex.length() - 1)]) % 255;
    return result;
}



Har ikke lige kompileret det. Har bare skrevet det ud fra de andre indlæg her i spørgsmålet :) Så håber det virker
Avatar billede mbulow Nybegynder
30. august 2008 - 21:24 #13
Hvad angår dit OT spørgsmål :)

Fejlen ligger her:

decryptedEncryption == encryptedDecryption == subject ? "Succes" : "Failure"

Du skal have et bool'sk udtryk på venstre side af ?-tegnet.

Det har du jo sådan set også, men du kan ikke skrive som du gør.

Du prøver at sammenligne tre string-objekter for at se om strengene er ens, men prøv at dele sætningen op og tag den én bid ad gangen.

Lad os for nemhedens skyld sige at resten at programmet virker, så de tre strenge ér ens.

Først
  'decryptedEncryption == encryptedDecryption'
Den sammenligning vil så give værdien 'true' (En boolsk værdi)

Nu sammenligner du
  'true == subject'
Det er der ikke så meget fornuft i. Du sammenligner en boolean værdi med et string-object.



Det er egentlig en meget fornuftig måde at tænke på det, men den går altså ikke i praksis.

Skriv i stedet, f.eks.:

((decryptedEncryption == subject) && (encryptedDecryption == subject)) ? "Succes" : "Failure"
Avatar billede Slettet bruger
30. august 2008 - 21:42 #14
Til de første to:
Ok. Jeg tror nu, jeg vil holde mig til den "primitive" opdeling - altså ren .cpp og ingen .h'er indtil videre.

Til den tredje:
Damn. Det virker i C#!!! :) Det skal være min faste undskyldning fra nu af.
Avatar billede Slettet bruger
30. august 2008 - 22:07 #15
Så! Nu virker det. Det vil sige - koden virker. Matematikken roder jeg stadig med. Jeg opretter måske et nyt spørgsmål med det, men lige nu siger jeg tak for hjælpen med programmeringen :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester