C Schleifenproblem

datalukas

Captain
Registriert
Dez. 2009
Beiträge
3.628
Hallo liebe Forenuser,

nachdem ich mich nach langem mal wieder ans Programmieren gemacht habe, weil ich auf diese Seite hier gestoßen bin, hab ich schon bei der ersten Aufgabe ein Problem:
http://projecteuler.net/problems

Quellcode sieht so aus:

Code:
#include "stdafx.h"

int main()
{
	int summe, test, x;
	summe = 0;
	for(x = 0; x > 1000; x++)
	{
		if(x % 3 == 0 || x % 5 == 0)
		{
			summe = summe + x;
		}
	}
	printf("Die Summe der Zahlen ist %i", &summe);
	scanf("%i", &test);
	return 0;
}

Ich arbeite mit Visual C++ 2010, deswegen das stdafx, stdio funktioniert da aus irgendwelchen Gründen nicht. Das scanf am Ende ist nur, damit das Fenster nicht gleich weg ist. Das Problem ist jedenfalls, dass bei jedem Durchgang immer andere Werte herauskommen, z.B. 1636712, 3735088 etc.

Bei einer While-Schleife ist es das Gleiche:

Code:
#include "stdafx.h"

int main()
{
	int summe, test, x;
	x = 0;
	summe = 0;
	while(x < 1000)
	{
		if(x % 3 == 0 || x % 5 == 0)
		{
			summe = summe + x;
		}
		x = x + 1;
	}
	printf("Die Summe der Zahlen ist %i", &summe);
	scanf("%i", &test);
	return 0;
}

Falls das ein Anfängerfehler war, verzeiht mir. Wie gesagt, es ist länger her. Allerdings hab ich das Gefühl, es hängt mit der IDE zusammen.
Gruß
Datalukas
 
probier mal x < 1002 anstatt x > 1000

wenn x = 0 ist und die abbruchbedingung x > 1000 (bei x=0 ist sie ja falsch) wird die schleife wie gesagt ganricht ausgeführt ;)
 
printf("Die Summe der Zahlen ist %i", &summe);
Denke du druckst hier die Addresse von Summe, was immer eine andere ist.
Folgendes sollte funktionieren:
Code:
printf("Die Summe der Zahlen ist %i", summe);


for(x = 0; x > 1000; x++)
Die Forschleife wird überhaupt nicht ausgeführt. Das sollte funktionieren:
Code:
	for(x = 0; x < 1000; x++)

Edit: Oops sorry für Doppelpost, wollte den ersten Beitrag bearbeiten
 
Wie gesagt, Anfängerfehler und ich hab wieder nicht genau geschaut. :D

Vielen Dank!

Ich hab noch ne Frage aus Interesse:

Wie kann eigentlich main eine get-Funktion (Datentyp int) sein?
 
Per Definition. Möglich ist auch void mit manchen Compilern, korrekt ist aber int.

main() gibt ja 0 zurück, wenn die Programmausführung ok war. Daher weiß dann auch das Betriebssystem, dass die Programmausführung erfolgreich beendet wurde (sog. "exit status"). Bei allem, was verschieden von 0 ist, ... probier es doch mal aus!
 
Zuletzt bearbeitet:
Ja, dass das return aus diesem Grund da ist war mir klar. Aber eigentlich geben ja solche Funktionen nur Werte zurück und können nichts anzeigen, dachte ich.
Ergänzung ()

Ich häng grad bei der dritten Aufgabe und frag mich, warum dieser Ansatz nicht richtig funktioniert:
Code:
int main()
{
	int zahl, x, test;
	zahl = 10;
	x = 2;
	while(zahl % x == !0)
	{
			x++;
	}
	while(zahl > x)
	{	
		zahl = zahl / x;
		while(zahl % x == !0)
		{
			x++;
		}
	}
	printf("%i", zahl);
	scanf("%i", &test);
}

Das Ganze geht nur bei Zahlen unter 10.
 
Zuletzt bearbeitet:
Was meinst du mit "anzeigen"? Ausgaben auf die Konsole? Du kannst selbst bestimmen, wann was ausgegeben wird, egal in welcher Methode.

Zu Aufgabe 3: Ich würde als nicht C-ler behaupten, dass !0 das Problem ist. Du meinst vermutlich: zahl % x != 0
 
Genau das war es. Vorhin hatte ich das schon mal als =! probiert (irgendwie dachte ich, dass es sorum wäre, hat aber nicht funktioniert, und dann dacht ich mir, das wäre ja das Gleiche.

Mir anzeigen meine ich das Ausführen von z.B. printf.
 
Ach, wie gesagt, ich habe mich schon länger nicht beschäftigt (und eigentlich habe ich mich mit C noch nie richtig intensiv beschäftigt), deswegen diese Fehler. Bei Problem 4 funktioniert es wieder nicht ganz richtig, wobei ich diesmal ziemlich nahe dran bin.

Code:
#include "stdafx.h"
int funktion(int zahl)
{
	unsigned char stelle[6];
	stelle[5] = zahl % 1000000 / 100000;
	stelle[4] = zahl % 100000 / 10000;
	stelle[3] = zahl % 10000 / 1000;
	stelle[2] = zahl % 1000 / 100;
	stelle[1] = zahl % 100 / 10;
	stelle[0] = zahl % 10;
	if(stelle[5] == stelle[0] && stelle[4] == stelle[1] && stelle[3] == stelle[2])
		return 1;
	else
		return 0;
}
int main()
{
	int test;
	int zahl1, zahl2;
	zahl1 = zahl2 = 999;
	while(funktion(zahl1*zahl2) == 0)
	{
		zahl2=zahl2-1;
		zahl1 = 999;
		while((funktion2(zahl1*zahl2) == 0) && (zahl1 > 100))
		{
			zahl1 = zahl1 - 1;
		}
	}
	printf("Die groesste Zahl ist %i , was %i * %i ist.", zahl1*zahl2, zahl1, zahl2);
	scanf("%i",&test);
	return 0;
}

Diesmal ist zumindest keiner der einfachen Fehler wie in den Aufgaben davor dabei. Aber das Ergebnis ist 580085 (583 * 995).
 
Da hast du natürlich Recht, aber bei so einer 6 Stellen reißt das, denke ich, auch nicht soviel raus. ;)
 
weniger von der performance her: der compiler wird wahrscheinlich die schleife sowieso "unrollen" und die einzelnen schritte explizit generieren, sodass der resultierende maschinencode identisch ist.

wenn mehrfach dasselbe gemacht werden soll, sollte man das möglichst auch nur einmal aufschreiben und dann mehrfach aufrufen, vermeidet fehler und verbessert die lesbarkeit.
 
Code:
int funktion(int zahl)
Das ist natürlich auch grausam. Man muss schon am Funktionsnamen erkennen, was die Funktion macht!

Natürlich kann man mit while-Schleifen arbeiten aber gerade solche Aufgaben sind auf jeden Fall schöner mit einer for-Schleife programmiert.

Inhaltlich: Du printest, dass die größte gefunden wurde sobald deine beiden whiles fertig sind aber das stimmt einfach nicht. Du findest zwar eine, aber (wahrscheinlich) nicht die größte.
Überleg dir mal, in welcher Reihenfolge die Zahlen durch dein Programm untersucht werden. Hier könntest du auch testweise die Werte von zahl1 und zahl2 printen. Alternativ mit einem Debugger die Werte der Variablen angucken.

Zum mathematischen Hintergrund, falls du nicht einfach stumpf alle 999*999 Möglichkeiten durchprobieren willst ein Tipp:
3*9 < 4*8 < 5*7 < 6*6 obwohl 3+9 = 4+8 = 5+7 = 6+6. Aber darum musst du dich natürlich nicht kümmern, um die Aufgabe allgemein zu lösen. Eine saubere "probiere alles aus und printe die größte"-Lösung ist für den Anfang super.
 
Zuletzt bearbeitet:
@maxwell

Haben das jetzt gar nicht leistungsmäßig gemeint, sondern eher von der Tipparbeit. Aber dazu noch:
Der Compiler generiert den Maschinencode also eh so, da die Schleife schon von vornherein eine eindeutige Wiederholungszahl hat, oder?

@kuddlmuddl Ja, funktion ist natürlich ein denkbar aussageloser Name, aber da das Programm ja eh nur eine Funktion hat, ist es in diesem Fall egal. Bei mehr Funktionen würde ich dann schon eindeutige Namen geben.

Ich habe verstanden, was das Problem ist, leider weiß ich jetzt aber nicht, wie ich das angehen soll. Eine Möglichkeit, wäre ja auch, einfach alle Palindrome zu suchen, und dann den größten auszuwählen, aber dann weiß ich ja nicht, wie viele Variablen ich erstellen soll oder wie groß das Array sein soll. Oder kann ich ein Array mit Größe x erzeugen, dessen Größe sich immer ändert?
 
der compiler hat die freiheit, das zu machen.

ob er das tut, hängt davon ab, ob er überhaupt versucht, optimierten code zu erzeugen, und davon, ob er es denn für schneller hält, wovon ich in diesem fall aber ausgehe.
 
Der Compiler versucht in solchen Fällen je nach Möglichkeit sogar, durch verschiedene Intra- und Interprozedurale Optimierungstechniken (Konstantenpropagation, Konstantenfaltung), möglichst das fertige Ergebnis schon auszurechnen. Das ist natürlich in letzter Konsequenz nur möglich, wenn der Returnwert der Schleife invariant ist, und dies mit den Methoden der Compileroptimierung analysierbar ist.

Es kann also gut sein, dass du irgendein vielzeiliges Schleifenkonstrukt baust, der "Maschinencode" des Compilers aber sinngemäß nur so aussieht:

"move to ergebnisregister 42;"
 
datalukas schrieb:
@maxwell
[...]Eine Möglichkeit, wäre ja auch, einfach alle Palindrome zu suchen, und dann den größten auszuwählen, aber dann weiß ich ja nicht, wie viele Variablen ich erstellen soll oder wie groß das Array sein soll. Oder kann ich ein Array mit Größe x erzeugen, dessen Größe sich immer ändert?

Du kannst auch in C dynamische Arrays erstellen, ist dort allerdings etwas aufwendiger als in anderen Sprachen (wenn's soweit ist, schau dir malloc und realloc an). Das ist allerdings hier gar nicht notwendig. Wenn du ein Array verwenden wolltest (wieder unnötig hier), dann könntest du das in dem konkreten Fall natürlich auch einfach mal so groß machen, dass auf jeden Fall alles reinpasst.

Das Problem in deinem Code liegt aber, wie auch von kuddlmuddl erwähnt, in deinen while-Schleifen. Schau sie dir an, das wird so nix. Die gehen nicht alles durch. Wenn du Tipps willst: Nimm For-Schleifen.
 
Noch ein Tipp: Alle Schleifen sind gleichwertig, weil alle Schleifen in alle anderen Schleifen überführt werden können.
 
Zurück
Oben