# C Programm zum Potenzieren - Fehler



## funnymonkey (4. Mai 2013)

Hallo an alle PCGH'ler da drausen,

ich bin gerade dabei mir C beizubringen und habe zum Üben ein Programm geschrieben, dass aus der Eingabe zweier Zahlen (base & exponent) die Potenz daraus berechnet. Eigentlich wollte ich damit ausprobieren, was passiert, wenn man die _pow()_ Funktion mit negativen Eingaben füttert. 
Mein Programm sieht bis jetzt so aus:

```
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
    double base;
    double exponent;
    double result;
    int temp;

    printf("Geben Sie die Basis ein, zu der potenziert werden soll:\n");
    temp = getchar();
    base = atof(temp);
    printf("Geben Sie den Exponenten ein:\n");
    temp = getchar();
    exponent = atof(temp);

    result = pow(base,exponent);

    printf("Ergebnis: %0.f", result);

    return 0;
}
```
Nun passiert folgendes: Wenn ich für die Basis ein Zahl eingebe und Enter drücke kommt die Windows 7 Fehlermeldung: Das Programm (hier: Potenzieren.exe) funktioniert nicht mehr. Es wird nach einer Lösung gesucht. Wieso kommt diese Fehlermeldung bzw. warum stürzt diese Programm ab? Vielen Dank schon mal im Voraus.

LG funnymonkey


----------



## crusherd (4. Mai 2013)

Hi,

Da du anscheinend mit Visual Studio arbeitest, würde ich dein Programm mit dem Debugger starten.

Edit:

Mit was kompilierst du das Programm?
Wenn ich deinen Code in VS2012 werfe, bekomme ich Compilier-Fehler und zwar für die Funktion atof().
Was erwartet atof()?


----------



## funnymonkey (4. Mai 2013)

Ich arbeite mit Code::Blocks und mingw-Compiler. Eine Fehlermeldung erhalte ich nicht. 

Laut C++ Reference erwartet _atof()_ einen String. Ich glaube so langsam dämmerts. Meine Eingabe ist durch _getchar()_ ein Integer. Ich werde es gleich ausprobieren, muss davor aber noch was erledigen. Danke für den Wink. 

LG funnymonkey


----------



## crusherd (4. Mai 2013)

Kein Problem. Jeder fängt mal klein an und dazu gehören auch nun mal Fehler. 

Falls du nicht weiterkommen solltest, habe ich eine Lösung, mit der du Zahlen ohne Probleme potenzieren kannst. (Basiert auf deinem Code) 

Gruß
crusherd


----------



## DarkMo (4. Mai 2013)

getchar liest ein einziges zeichen ein. ein 3.5 könntest du also nie einlesen, sondern nur integer zahlen zw 0 und 9 ^^ probier doch mal eher scanf aus - das ließt ne zeichenkette ein bis du enter drückst. natürlich kann atof (char zu float) "hallo" dann nich umwandeln ^^


----------



## crusherd (4. Mai 2013)

statt scanf() kann man auch gets() verwenden.


----------



## funnymonkey (4. Mai 2013)

Das kam in meinem Buch ("C für Dummies") auch schon vor, nur war ich mir nicht mehr sicher, welche der beiden Funktionen das Enter mit ausliest. Deshalb hab ich zum Ausprobieren _getchar()_ genommen. 
Ich habe den Code wie folgt abgeändert:

```
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
    double base;
    double exponent;
    double result;
    char temp [20];

    printf("Geben Sie die Basis ein, zu der potenziert werden soll:\n");
    scanf("%s", temp);
    base = atof(temp);
    printf("Geben Sie den Exponenten ein:\n");
    scanf("%s", temp);
    exponent = atof(temp);

    result = pow(base,exponent);

    printf("Ergebnis: %2.f", result);

    return 0;
}
```
Jetzt funktionierts.  Aber nur mit den Zahlen von 0-9. Wenn ich z.B. 1536 und 1256 eingebe kommt als Ergebnis 1 raus. Wieso? Hat _float_ nur eine Stelle vor dem Komma?

@crusherd: Ist das ungefähr so, wie du es gelöst hast?

Nochmals danke an alle. 
Eine Frage hätte ich noch, ist zwar Off-Topic, aber egal: Kennt ihr eine populäre Anwendung, die auf C basiert? 

LG funnymonkey


----------



## nay (4. Mai 2013)

1. Warum nutzt du scanf nicht, um direkt in die double Variable zu lesen?? scanf("%lf", &base)
2. Das Ergebnis 1536 hoch 1256 ist zu groß, um von double dargestellt zu werden.


----------



## funnymonkey (4. Mai 2013)

1. Ich weiß nicht wie das geht. Zu was ist das _&_ vor _base_?
2. Ok. Aber das Komma lässt sich verschieben, oder? Wie kann ich so große Zahlen darstellen?

Edit: Ich habe das jetzt so abgeändert:
	
	



```
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
    long double base;
    long double exponent;
    long double result;

    printf("Geben Sie die Basis ein, zu der potenziert werden soll:\n");
    scanf("%Lf", &base);
    printf("Geben Sie den Exponenten ein:\n");
    scanf("%Lf", &exponent);

    result = pow(base,exponent);

    printf("Ergebnis: %2.Lf", result);

    return 0;
}
```
Geht aber trotzdem nicht. Auch nicht mehr mit Zahlen <9.


----------



## crusherd (4. Mai 2013)

Hey,

Wie nay schon geschrieben hat, du kannst mit scanf direkt ein double einlesen. Das & wird benötigt, da scanf einen Zeiger auf Speicher erwartet, in den es schreiben kann. Du lieferst mit &base quasi einen Zeiger ( genau genommen die Adresse von base) wohin scanf schreiben soll.

So eine ähnliche Lösung wie du habe ich. 
Morgen kann ich dir meine Lösung und paar hilfreiche Tipps geben, wo man sucht. Bin leider imo nur mobil hier. 

Eine erste Anlaufstelle ist www.cplusplus.com und die dortige C-Bibliothek.


Gruß
crusherd


----------



## Leandros (4. Mai 2013)

crusherd schrieb:


> statt scanf() kann man auch gets() verwenden.


 
Oder klassisch 'cin'.


----------



## DarkMo (4. Mai 2013)

nuja, wies scheint lernt er grade erstmal puristisches c ^^ kann mich natürlich auch irren. aber dann gäbe es kein cin


----------



## Leandros (4. Mai 2013)

DarkMo schrieb:


> nuja, wies scheint lernt er grade erstmal puristisches c ^^ kann mich natürlich auch irren. aber dann gäbe es kein cin


 
Ohh, stimmt. Dann halt stdin.


----------



## nay (4. Mai 2013)

Für Zahlen, die die Länge von double überschreiten gibt es keinen Standarddatentyp. Es gibt sicher Bibliotheken, die du einbinden könntest, um größere doubles zu bekommen.
Das "&" vor dem Parameter steht in diesem Fall dafür, dass die Variable durch die Funktion verändert wird. In deinem C Buch wird das sicher in den nächsten Kapiteln genauer behandelt.

Was meinst du mit "geht nicht"???


----------



## crusherd (5. Mai 2013)

Hi,

So wie versprochen mal der Code. Dies ist nur eine mögliche Lösung:

```
[COLOR=black]#include <stdio.h>[COLOR=black]#include <stdlib.h>[COLOR=black]#include <math.h>
[COLOR=black]int main(){[COLOR=black]double base = 0;[COLOR=black]double exponent = 0;[COLOR=black]double result = 0;
[COLOR=black]printf("Geben Sie die Basis ein, zu der potenziert werden soll:\n");[COLOR=black]scanf("%lf", &base);[COLOR=black]printf("Geben Sie den Exponenten ein:\n");[COLOR=black]scanf("%lf", &exponent);
[COLOR=black]result = pow(base,exponent);
[COLOR=black]printf("Ergebnis: %.2f\n", result);
[COLOR=black]return 0;[COLOR=black]}
```

Anleitungen, wie man scanf() und printf() verwendet:
scanf - C++ Reference

printf - C++ Reference

Außerdem ist die Seite sehr hilfreich beim Programmieren:
Stack Overflow

Wenn dein Programm nicht das tut, was es soll, solltest du mal dein Programm debuggen. Damit hast du die Möglichkeit zu sehen, was dein Programm macht und welche Werte deine Variablen haben bzw. bekommen.
Wie das mit Code::Blocks und mingw geht, weiß ich leider auf die Schnelle nicht, da müsstest du mal die Anleitung dazu lesen.

Gruß
crusherd


----------



## funnymonkey (5. Mai 2013)

@crusherd: Cool, sieht fast so aus wie mein Quellcode. Warum initalisierst du die Variablen am Anfang mit 0? Falls die Speicheradresse noch nicht gelöscht ist?

Am Anfang konnte ich noch Zahlen, die kleiner als 9 waren, potenzieren. 
Mittlerweile (Code geändert wie in Post #9) ist es so, dass ich auch bei 9 hoch 9 als Ergebnis -2 bekomme. Obwohl die Datentypen allesamt vom Typ  _long double_. Ich habe im Quellcode zum Ausprobieren die Datentypen in _double_ umgewandelt. Dann funktioniert es, ich kann aber nicht die Vorteile von _long double_ nutzten. Stimmt es, dass man um mit _scanf()_ einen _long double_ in die entsprechende Variable zu speichern, man das kleine l durch ein große ersetzen muss?

Und ja, ich lerne puristisches, einfachstes C. Aber www.cplusplus.com hilft gerade als Nachschlagewerk schon extrem.

LG funnymonkey


----------



## crusherd (5. Mai 2013)

Mingw verwendet unter Windows den Microsoft Compiler. Für Microsoft sind 
	
	



```
long double
```
 und 
	
	



```
double
```
 das gleiche. Warum das so ist, kann dir nur Microsoft verraten.

Was ich dazu gefunden habe:
mingw - Conversion specifier of long double in C - Stack Overflow

Edit:
Ja, du hast recht mit dem l -> L für long double. 

Gruß
crusherd


----------



## funnymonkey (5. Mai 2013)

@crusherd: Typisch Mircosoft, tztztz... .

Danke @ all. Jetzt funktioniert das so, wie ich es mir gedacht habe. Ihr habt mir echt geholfen.

LG funnymonkey


----------



## crusherd (5. Mai 2013)

kein Thema. 

Falls du irgendwann mit Linux arbeiten willst, empfehle ich dir den clang compiler zu holen und mit dem zu arbeiten, da er gesprächiger und hilfsbereiter ist als der gcc. 

Gruß
crusherd


----------



## DarkMo (5. Mai 2013)

noch eine simple (und nicht immer nutzbare) debugmethode ist das "echo debugging". ich habs in zusammenhang mit php (ausgaben per echo-befehl) kennengelernt. besagt nix anderes, als dass man zur überprüfung der werte zur laufzeit, diese einfach ausgeben lässt ^^ wie gesagt, simpel aber oft dennoch nützlich.


----------



## Triniter (14. Mai 2013)

DarkMo schrieb:


> noch eine simple (und nicht immer nutzbare) debugmethode ist das "echo debugging". ich habs in zusammenhang mit php (ausgaben per echo-befehl) kennengelernt. besagt nix anderes, als dass man zur überprüfung der werte zur laufzeit, diese einfach ausgeben lässt ^^ wie gesagt, simpel aber oft dennoch nützlich.


 Jepp, typisches printf-debugging. Wird teilweise während der Entwicklung sogar in Embedded Projekten eingesetzt, da ist dann halt die Standardausgabe nicht ein Monitor sondern z.B. eine serielle Schnittstelle. Wenn du also dein Projekt von vorhin hernimmst kannst du folgendes machen:


```
[COLOR=black]#include <stdio.h> 
[COLOR=black]#include <stdlib.h> 
[COLOR=black]#include <math.h>  
[COLOR=black]int main()
{   [COLOR=black]double base = 0;   [COLOR=black]double exponent = 0; [COLOR=black]  double result = 0;   [COLOR=black]printf("Geben Sie die Basis ein, zu der potenziert werden soll:\n"); [COLOR=black]
   scanf("%lf", &base);   printf("Debugausgabe Basis: %f/* oder %e*/\n", base);
   [COLOR=black]printf("Geben Sie den Exponenten ein:\n"); 
   [COLOR=black]scanf("%lf", &exponent); 
   printf("Debugausgabe Exponent: %f/* oder %e*/\n", [COLOR=black]exponent); 
   [COLOR=black]result = pow(base,exponent);  
   [COLOR=black]printf("Ergebnis: %.2f\n", result);  
   [COLOR=black]return 0; 
[COLOR=black]}
```

Interessant wird die Aufgabe jetzt noch wenn du hingehst und nicht die Funktion pow() verwendest sondern versuchst die Funktion selbst zu erstellen.


----------



## fadade (14. Mai 2013)

Triniter schrieb:


> Interessant wird die Aufgabe jetzt noch wenn du hingehst und nicht die Funktion pow() verwendest sondern versuchst die Funktion selbst zu erstellen.


 
Nä 
Nicht unbedingt die performanteste Lösung, aber funktional (Java/C#-Code):


```
/// Berechnet k  ^ n
            /// Negative Potenzen erlaubt
            public static double exp(double k, int n)
            {
                double erg = 1.0;

                if (n == 1)
                {
                    return k;
                }
                else if (n > 1)
                {
                    while (n-- > 0)
                    {
                        erg *= k;
                    }
                }
                else if (n < 0)
                {
                    erg = 1 / exp(k, -n);
                }

                return erg;
            }
```


----------



## funnymonkey (15. Mai 2013)

Wenn ich das richtig verstehe wird bei printf-debugging jeder Schritt durche eine _printf()_ Funktion ausgegeben und es lässt sich so feststellen, bei welchem Schritt es hakt. Oder?

@fadade: Was wäre denn performanter? Schon mit vorberechneten Werten arbeiten und in deinem Fall _n_ ungefähr einordnen?


----------



## DarkMo (15. Mai 2013)

man muss ned überall ne ausgabe bauen, aber man kann es natürlich ^^ am besten schreibt man dann sowas wie "stelle so und so im code, variable bla hat wert blubb". oder man schreibt einfach nur 1 2 3 4 pro print und kann dann sehen, aha, bis zur 3 is er gekommen, die 4 führt er scho ned mehr aus, also muss irgendwo nach dem print(3) befehl was im argen sein ^^

wie gesagt, stell dir darunter nix kompliziertes oder weltbewegendes vor.


----------



## fadade (15. Mai 2013)

funnymonkey schrieb:


> Wenn ich das richtig verstehe wird bei printf-debugging jeder Schritt durche eine _printf()_ Funktion ausgegeben und es lässt sich so feststellen, bei welchem Schritt es hakt. Oder?



Sinnvollerweise platziert man die Debug-Ausgaben nur an den Stellen, wo "kritische"/wichtige Aktionen passieren. Darüber hinaus kannst du die Ausgaben auch noch etwas tiefergehend modifizieren, sprich wenn sich eine Variable x aus den Werte 325, y, 2*k, ... zusammensetzt kannst du entweder nur das Ergebnis x ausgeben oder sowas wie "x=[wert], zusammengesetzt aus y=[wert], k=[wert] ...". Das macht die Rückverfolgung einfacher. Ich würde mal sagen, dass man aus dieser Form des "Debuggens" keine so große Wissenschaft machen sollte; man gibt halt aus, was halbwegs sinnvoll ist und zur Fehlerfindung beiträgt 



funnymonkey schrieb:


> @fadade: Was wäre denn performanter? Schon mit vorberechneten Werten arbeiten und in deinem Fall _n_ ungefähr einordnen?


Vorberechnete Werte machen wenig Sinn, dazu ist der kombinatorische Wertebereich zu groß. Allerdings kann man hier gut antworten mit "kommt auf die Eingabedaten an" 
Es kann ja sein, dass die Methode seeehr oft, mit eher kleinen Potenzen aufgerufen wird, oder nicht so oft, aber dafür mit höheren Potenzen, oder auch immer nur mit negativen Werten oder oder. Da könnten mehrere separate Methoden dann performanter sein - sind aber auch nicht so flexibel. Auf Ebene des Maschinencodes (wie es wohl bei der verfügbaren pow-methode der Fall sein wird) kann man da natürlich auch noch etwas drehen ... mir war einfach eine funktionale Methode wichtig


----------

