Plain C und Pointer

Psycho-Dad

Psycho-Dad

Aktives Mitglied
Thread Starter
Dabei seit
06.02.2005
Beiträge
272
Reaktionspunkte
2
Hi Leute,

ich hätte eine kleine Frage zu C und den tollen Pointern.

Ich habe heut zwei kleine Programme geschrieben, eines zur Zinsberechnung und ein zweites um einzelne Zeichen einer Zeichenkette auszutauschen. In beiden Fällen wird die eigentliche Arbeit in von einer kleinen Subroutine vorgenommen.

Im Falle der Zinsberechnung wird diese mit berechnung(&betrag, zinssatz) aufgerufen, im Falle der Zeichenoperation mit ersetze(string, 'e', 'E') .

Nun meine eigentliche Frage, im ersten Fall übergebe ich an die Sub ja nur die Adresse des Speicherbereichs in dem betrag steht. In der Sub wird dann mittels Pointer auf diesen Bereich gerechnet. Das ist für mich soweit verständlich.

Aber warum übergebe ich im zweiten Fall nur die Variable und nicht deren Speicherbereich wenn die Sub doch einen Pointer und somit einen Speicherbereich erwartet???

Ich häng beide Programme nochmal an, beide funktionieren nur beim zweiten verstehe ich eben nicht warum.

Zinsberechnung
Code:
#include <stdio.h>

float berechnung (float *betrag, float zinssatz) {
	float hilf = *betrag;
	/*printf("\n Aktuelle für Berechnung verwendeter Betrag: %f", *betrag);*/
	*betrag = hilf*zinssatz;
	return 0;
}

int main () {
	int i;
	int laufzeit;
	float zinssatz;
	float betrag;
	printf("Betrag in Euro: ");
	scanf("%f", &betrag);
	printf("\nLaufzeit in Monaten: ");
	scanf("%i", &laufzeit);
	printf("\nZinssatz in Prozent: ");
	scanf("%f", &zinssatz);
	zinssatz = 1 + (zinssatz/100);
	printf("\n");
	for (i=1; i<=laufzeit; i++) {
		berechnung(&betrag,zinssatz);
		printf("\nBetrag in Euro nach %i Monaten Laufzeit: %.2f", i, betrag);
	}
	return 0;
}

Zeichenkette
Code:
#include <stdio.h>
#include <string.h>
#define MAX_STRING 80

void ersetze (char *str, char alt, char neu) {
	while (*str) {
		if (*str==alt) {
			*str = neu;
		}
		*str++;
	}
}

int main () {
	char string[MAX_STRING];
	strcpy(string,"In diesem Satz wird e durch E ersetzt");
    ersetze(string, 'e', 'E');
	printf("\n%s",string);
	return 0;
}
 
spontan würde ich sagen, das liegt an dem char array und wie das in C generell implementiert ist...
 
Hallo,

der Name eines Arrays (in Deinem Fall string) selbst, d.h. ohne eckige Klammern ist immer ein Pointer.

ersetze(string, 'e', 'E');

ist das gleiche wie

ersetze(&string[0], 'e', 'E');

Viele Grüße
Klaus
 
  • Gefällt mir
Reaktionen: Psycho-Dad
re

Oh vielen Dank,

jetzt nur noch Felder kapieren und dann bin ich hoffentlich gewappnet für die IV Klausur am Freitag.

Zumindest ist OpenBook, da wird der Mr. Ritchie höchst persönlich mit in die Prüfung geschleift.
 
Was verstehst du bei Arrays nicht?

Arrays sind ein Speicherbereich, gefüllt mit einer festen Menge eines Datentyps.

Code:
// Define my favorite struct to demo arrays
struct sTyp {
  int i;
  double d;
};
typedef struct sTyp Typ; //set a typedef for easyer name handling

//my array will hold the type 100 times
int SIZE = 100;
//so allocate the aproproate memory
Typ[] t = (Typ[])malloc(SIZE*sizeof(Typ);

//fill the array, aka the memory, with some data
for (int i = 0; i < SIZE; i++) {
  t[i].i = i;
  t[i].d = sqrt(i);
}

//now you can readout
for (int i = 0; i < sizeof(t); i++) {
 printf("%d is he squareroot of %i", t[i].d, t[i].i);
}

oder so
 
Zuletzt bearbeitet:
Und ein char [] ist eben genau das: Ein Speicherbereich, der mit chars gefüllt wird

Alex
 
Na ja, andere Programmiersprachen sehen für Strings und Arrays andere Lösungen als "Ist einfach ein Zeiger" vor. Das dürfte eher eine C-Spezialität sein, die zudem wohl durch die maschinennahe Historie zu erklären ist. Zwingend ist das wahrlich nicht.
 
  • Gefällt mir
Reaktionen: below
Hi,

in Eurer Klausur geht es um Pointer, richtig?
Einfach nur grauenhaft, dass Ihr sowas noch lernen müsst - archaischer gehts kaum mehr...

Deine Berechnungsfunktion geht auch ohne diese verwirrende und hässliche Zeigerarithmetik (wird aber wahrscheinlich so verlangt, oder?), im Ansatz machst Du es sogar schon, nämlich über den Rückgabewert, der im Augenblick noch nutzlos ist. Poste es Dir mal hier:

#include <stdio.h>

float berechnung (float betrag, float zinssatz) {
return betrag*zinssatz;​
}

int main () {

int i;
int laufzeit;
float zinssatz;
float betrag;
printf("Betrag in Euro: ");
scanf("%f", &betrag);
printf("\nLaufzeit in Monaten: ");
scanf("%i", &laufzeit);
printf("\nZinssatz in Prozent: ");
scanf("%f", &zinssatz);
zinssatz = 1 + (zinssatz/100);
printf("\n");
for (i=1; i<=laufzeit; i++) {

betrag = berechnung(betrag,zinssatz);
printf("\nBetrag in Euro nach %i Monaten Laufzeit: %.2f", i, betrag);​
}
return 0;​
}

Im zweiten Listing bist Du auf Gedeih und Verderb darauf angewiesen, dass das übergebene char Array Nullterminiert ist, die ein klein wenig sicherere Variante wäre folgende:

#define MAX_STRING 80

void ersetze (char *str, char alt, char neu) {
int i;
for ( i = 0; i < MAX_STRING; i++) {
if ( str == alt) {
str = neu;

}

}

}

Diese mächtige, aber überaus gefährliche Zeigerarithmetik aus C ist sicher für den Grossteil aller Sicherheitslücken die massenhaft auftreten verantwortlich.

An welcher Uni und in welchem Studiengang schreibt Ihr die Klausur?

Beste Grüße, SMJ

P.S.: Bitte entschuldigt die furchtbare Einrückung mit den Leerzeilen, habe es nicht gerafft, wie man das mit der Forensoftware richtig macht
 
Einfach nur grauenhaft, dass Ihr sowas noch lernen müsst - archaischer gehts kaum mehr...

Na ja, das kann man so und so sehen. Wenn ich mir anschaue, wie manchen jungen Entwicklern einfach jegliches Verständnis darüber fehlt, was Speicher ist, und wie er organisiert ist, dann finde ich das schon ganz richtig, dass man etwas über Pointer lernt.

Alex
 
  • Gefällt mir
Reaktionen: Sir_RamDac und mq.
re

Weil wir schon gerade dabei sind, wäre von euch vielleicht jemand so nett mir zu erklären was folgender Code macht. Ich habe ihn in einer alten Klausur entdeckt und komm irgendwie nicht nocht so recht dahinter.

Code:
#include <stdio.h>
#include <stdlib.h>
#define N 6

struct elem {
	int *wert_p;
	int zahl;
	struct elem *next;
};

int main (void) {
    struct elem *L = NULL, *H;
	int i;
	
	for (i=1; i<N; i++) {
		H = malloc(sizeof(struct elem));
		H -> wert_p = malloc(sizeof(int));
		*(H->wert_p) = 5 * i;
		H -> zahl = *(H->wert_p) + 2 * i;
		H -> next = L;
		L = H;
	}
	i=1;
	H=L;
	while(H) {
		printf("Das %i. Element enthält: %3d %3d \n", i++, *(H->wert_p), H->zahl);
		H = H -> next;
	}
	while (H != NULL) {
		L = H -> next;
		free(H->wert_p);
		free(H);
		H=L;
	}
	return 0;
}

Also so wie ich das sehe definiere ich am Anfang eine Art Array als neuen Datentyp mit 3 Feldern. Aber danach beißt es auch schon aus.

Wäre toll wenn da noch jemand Klarheit reinbringen könnte. C Programmierung ist zwar nur ein kleiner Anteil an der Klausur morgen aber trotzdem würde ich gern bestehen ;)

EDIT: Ich schreibe die Klausur an der FH Regensburg, das Fach nennt sich Informationsverarbeitung und ist ein Fach aus dem Grundstudium des Studiengangs Mikrosystemtechnik. Aber irgendwie bin ich froh, wenn ich mir anschauen mit welchen Programmiersprachen sich Maschinenbauer oder E-Techniker rumärgern müssen (TurboPascal, VisualBasic) da hab ich es mit C direkt noch gut getroffen. Zu dem Fach gehört aber nicht nur C, der Großteil ist Digitaltechnik mit Bool'scher Algebra, KV-Diagrammen usw.

Ich hab außerdem festgestellt das man bei dem Programm für Zinsberechnung die Berechnung auch so durchführen könnte:
Code:
*betrag *= zinssatz
ist das ok, oder führt das zu Problemen?

CYA
Flo
 
Zuletzt bearbeitet:
im Normalfall möchte ich zu neuen Themen bitte auch neue Threads sehen. Da es hier aber wieder um C und Pointer geht und mit Nachsicht auf den Lernstreß sei das hier so geduldet!
 
@SMJ
Pointerarithmetik ist ja auch mehr als nur Speicherverwaltung. Primär geht es doch um den Unterschied "call by reference" und "call by value"! Wenn du die Methode änderst, dass nicht mehr die Adresse übergeben wird, änderst du möglicherweise auch das ganze Verhalten des Programms! Was, wenn in der Funktion die auf der Adresse liegende Variable manipuliert wird? In deinem Fall hat das nach außen hin keine Auswirkungen. Die Variable ist nur local gültig (call by value). Im Original ist dem aber nicht so (call by reference)!

Ich bin auch der Meinung, dass solche Mechanismen direkt vermittelt werden sollten, um zu verstehen, wie andere Programmiersprachen mit diesen Konzepten umgehen (zB. für Java wird jedes Objegt grundsätzlich call by reference adressiert, erst ein expliziter obj.clone() erlaubt call by value)

@Flo
Dein Beispiel zeigt nicht ein Array, sondern eine verkettete Liste..
 
Zuletzt bearbeitet:
Weil wir schon gerade dabei sind, wäre von euch vielleicht jemand so nett mir zu erklären was folgender Code macht. Ich habe ihn in einer alten Klausur entdeckt und komm irgendwie nicht nocht so recht dahinter.

ist eine einfach verkette liste, in deren elementen struct (ein struct ist übrigens kein array, sondern fast mehrere daten typen zu einem zusammen) halt 2 werte drin sind, einmal als pointer auf int und einmal als int und dann halt ein zeiger auf das nächste element.
der int pointer wird in einer schleife mit 5 * i gefüttert und dann halt die zahl mit dessen wert + 2 * i. danach wird noch der zeiger auf das nächste element gesetzt...

hattet ihr keine einfach und doppelt verketteten listen als beispiele?
das wird doch gerne immer gemacht, speziell für die ganzen sortier verfahren...
 
  • Gefällt mir
Reaktionen: Psycho-Dad
In dieser Aufgabe geht es nicht um Arrays sondern um verkettete Listen.
Wieder eine kranke und unzeitgemäße Implementation :)

Code:
#include <stdio.h>
#include <stdlib.h>
#define N 6

// Listenelement definieren
struct elem {
// Zeiger für zu speichernden Wert
	int *wert_p;
// enthält den Inhalt von wert_p plus zweimal die Indexpostion in der verk. Liste
	int zahl;
// Zeiger auf den nächsten Eintrag in der Liste
	struct elem *next;
};

int main (void) {
    struct elem *L = NULL, *H;
	int i;

// Aufbau der verketteten Liste, insgesamt 6 Durchläufe	
	for (i=1; i<N; i++) {
// Speicher für nächstes Element besorgen
		H = malloc(sizeof(struct elem));
// Speicher für Wert besorgen
		H -> wert_p = malloc(sizeof(int));
// wert_p initialisieren, 1=5,2=10,3=15 usw.
		*(H->wert_p) = 5 * i;
// zahl initialisieren, 1=7, 2=14,3=21 usw.
		H -> zahl = *(H->wert_p) + 2 * i;
// Zeiger für verkettet Liste, diese wird rückwärts aufgebaut, der letzte Eintrag zeiht auf NULL zur Terminierung derselibigen
		H -> next = L;
// L für den nächsten durchlauf auf den Speicher für das Element h setzen (1.Elem->next = 2.Elem, 2.Elem->next = 3.Elem, 3.Elem->next = 4.Elem, 4.Elem->next=5.Elem, 5.Elem->next=6.Elem, 6.Elem->next = NULL, dh Ende der Liste)
		L = H;
	}
	i=1;
	H=L;
// Ausgabe der Liste, Schleife bricht nach dem letzten Element ab - NULL s.o.
	while(H) {
		printf("Das %i. Element enthält: %3d %3d \n", i++, *(H->wert_p), H->zahl);
		H = H -> next;
	}
// Speicher wieder freigeben
	while (H != NULL) {
		L = H -> next;
		free(H->wert_p);
		free(H);
		H=L;
	}
	return 0;
}
Flo

Gruß, SMJ
 
  • Gefällt mir
Reaktionen: Psycho-Dad
re

Ich behaupte jetzt einfach mal nicht, das Fach war schon immer ein kleines Problemkind. Du hast 3 Dozenten und jeder verzählt dir irgendwas. Ein guter Kumpel der 2 Semester über mir studiert musste das fast komplett ohne C Wissen schreiben. Der Dozent der C gab war ein Tscheche und hielt die Vorlesung teilweise in seiner Muttersprache. Der wurde aber nach einem Semester ausgetauscht. Ich hatte dann einen wirklich fähigen C Mann, der hat aber auch nur ein Semster durchgehalten. Und der es jetzt gibt erklärt die komplette Programmiersprache anhand von Flussdiagrammen.

Ich bin echt heilfroh wenn ich die Klausur hinter mir hab und hoffentlich bestehe. Ist mein Zweitversuch und ich hab keine Lust darauf auch noch einen Drittversuch zu verwenden zumal diese ja eh sehr begrenzt sind.

Aber auf jeden Fall sehr vielen Dank nochmal für all eure Hilfe, ich glaube damit sind all meine Fragen für die Klausur geklärt. Und wenn ihr mir noch einen kleinen gefallen tun wollt dann drückt mir morgen zwischen 15.00 und 17.00 die Daumen. Jetzt darf ich mich dem nächsten tollen Fach widmen, BWL ;)
 
In dieser Aufgabe geht es nicht um Arrays sondern um verkettete Listen.
Wieder eine kranke und unzeitgemäße Implementation :)



Gruß, SMJ

Danke für dein hilfreiches Statement... :rolleyes: Hier geht es um Lehre und nicht um modernes Programmieren. Gegenfrage: Wie erzeugst du mit C einen beliebig langen Vector ohne Pointer und Verkettete Listen?

Ganz nebenbei: ganz so archaisch ist C nicht! ZB Im Embedded- und Automotive-Bereich wird bevorzugt mit C programmiert, da der Footprint der erzeugten Programme kleiner als der von objektorientierten Sprachen mit automatischer Speicherverwaltung ist.
 
@SMJ
Pointerarithmetik ist ja auch mehr als nur Speicherverwaltung. Primär geht es doch um den Unterschied "call by reference" und "call by value"! Wenn du die Methode änderst, dass nicht mehr die Adresse übergeben wird, änderst du möglicherweise auch das ganze Verhalten des Programms! Was, wenn in der Funktion die auf der Adresse liegende Variable manipuliert wird? In deinem Fall hat das nach außen hin keine Auswirkungen. Die Variable ist nur local gültig (call by value). Im Original ist dem aber nicht so (call by reference)!

Ich bin auch der Meinung, dass solche Mechanismen direkt vermittelt werden sollten, um zu verstehen, wie andere Programmiersprachen mit diesen Konzepten umgehen (zB. für Java wird jedes Objegt grundsätzlich call by reference adressiert, erst ein expliziter obj.copy() erlaubt call by value)
Hi ebm,

stimmt, habe aber auch nicht behauptet, dass Pointerarithmetik nur Speicherverwaltung ist. Trotzalledem erfordert sie ein tiefes Verständnis von C und ist für Anfänger starker Tobak. Warum sonst abstrahieren sie alle modernen Sprachen weg, selbst in C++ mit der STL kommt man viel seltener damit in Berührung. Da gibt dann auch den Reference-operator & (oder wie auch immer man ihn richtig nennt) für call-by-value/call by reference.

Ich denke nicht, dass man sowas am Anfang vermitteln muss (C-Pointerarithmetik), es verwirrt nur und erzeugt grauenhaft unleserlichen Code (in Leipzig an der HTWK sind die Studis massenhaft eingebrochen damit).

Mein Beispielcode oben ist zu Demonstrationszwecken gedacht...ich denke nicht, dass das Internet deswegen abstürzt :)

Gruß, SMJ
 
Die armen Anfänger. Yo mei, die studieren an ner Uni! Da kann man schon etwas Hirnschmalz erwarten.. Mein letztes Statement dazu *und wech*
 
Ich denke nicht, dass man sowas am Anfang vermitteln muss (C-Pointerarithmetik), es verwirrt nur und erzeugt grauenhaft unleserlichen Code (in Leipzig an der HTWK sind die Studis massenhaft eingebrochen damit).

gerade das sollte man, weil pointer nun mal mit zum handwerk gehören und da auch die meisten probleme auftreten, weil gerne mal nicht auf null gecheckt wird bevor man den pointer anspringt ;)
deswegen haben neuere sprachen wie java ja keine pointer mehr...
 
float berechnung (float *betrag, float zinssatz) {
float hilf = *betrag;
/*printf("\n Aktuelle für Berechnung verwendeter Betrag: %f", *betrag);*/
*betrag = hilf*zinssatz;
return 0;
}

return 0.0;
Oder sehe ich das jetze falsch? Werde ich zum Korintenkacker? ;)
 
Zurück
Oben Unten