Hilfe bei Matrixmultiplikation in C als Funktion



  • wobei sich anzahlspalten natürlich auf die tatsächliche anzahl bezieht.
    wenn du also eine 10*10 matrix hast, ist anzahlspalten auch 10, erstellst du ein array mit 10*10 elementen, schreibst da aber nur eine 3*5 matrix rein, so ist anzahlspalten auch 10, obwohl du nur 3 spalten hast.



  • Das Transponieren habe ich ja so bewerkstelligt, dass in der 1. matrix spaltenweise schnell gezählt wird und in der 2. matrix zeilenweise.



  • wobei sich anzahlspalten natürlich auf die tatsächliche anzahl bezieht. 
    wenn du also eine 10*10 matrix hast, ist anzahlspalten auch 10, erstellst du ein array mit 10*10 elementen, schreibst da aber nur eine 3*5 matrix rein, so ist anzahlspalten auch 10, obwohl du nur 3 spalten hast.
    

    Oh GOOOOOOOTT wieso hab ich das nicht gecheckt ?! Das war die ganze Zeit der verbliebende Fehler!!
    Ich könnte heulen!
    Okay, ich hoffe wenigstens, dass das gesamte Prozedere auch in Zukunft anderen helfen wird, die hierüber stolpern.
    Hier ist der gesamte Code für Teilaufgabe b:

    #include <stdio.h>
    #include <stdlib.h>
    
    int multiplikation(int *matrix1,int *matrix2,int *ergebnis,int a1,int a2,int b1, int b2,int h1, int h2){
    	int h3, Summe=0;
    	for (h1 = 0; h1 < a1; h1++){
    				for (h2 = 0; h2 < b2; h2++){
    					for (h3 = 0; h3 < b1; h3++){
    						Summe = Summe + *(matrix1+h1*10+h3)**(matrix2+h3*10+h2);
    					}
    				*(ergebnis + h1*10+h2) = Summe;
    				Summe= 0;
    				}
    			}
    	return *ergebnis;
    }
    
    int main(void){
    	int a1,a2,b1,b2;
    	int h1,h2=0;
    	int matrix1[10][10], matrix2[10][10],ergebnis[10][10];
    	printf("Zeilen der ersten Matrix angeben:");
    	scanf("%i",&a1);
    	printf("Spalten der ersten Matrix angeben:");
    	scanf("%i",&a2);
    	printf("Zeilen der zweiten Matrix angeben:");
    	scanf("%i",&b1);
    	printf("Spalten der zweiten Matrix angeben:");
    	scanf("%i",&b2);
    	if (a2!=b1){
    		printf("Die Matrizen k�nnen nicht multipliziert werden!\n");
    	}
    	printf("Elemente der ersten Matrix eingeben(v.l.n.r.)");
    				for (h1 = 0; h1 < a1; h1++){
    				    for (h2 = 0; h2 < a2; h2++){
    				    	scanf("%i", &matrix1[h1][h2]);
    				    }
    				}
    				printf("Elemente der zweiten Matrix eingeben(v.l.n.r.)");
    				for (h1 = 0; h1 < b1; h1++){
    					for (h2 = 0; h2 < b2; h2++){
    						scanf("%i", &matrix2[h1][h2]);
    					}
    				}
    	multiplikation(*matrix1,*matrix2,*ergebnis,a1,a2,b1,b2,h1,h2);
    	for (h1 = 0; h1 < a1; h1++) {
    					for (h2 = 0; h2 < b2; h2++){
    						printf("%i\t", ergebnis[h1][h2]);
    					      }
    					printf("\n");
    					}
    return 0;
    }
    

    Für eure Geduld und eure Erklärungen UND eure kostbare Zeit danke ich euch vielmals. Ich denke, es kann einen schon zur Verzweiflung bringen, wenn die Gegenseite ein wahrscheinlich simples Problem nicht versteht.
    Aber hey, die Aufgabe war für mich sehr wertvoll um mein Verständnis für diese Programmiersprache zu erweitern.

    Der Offset vom a vom Anfang des Array ist 2 * 10 + 4 = 24.
    Auch wenn der gefüllte Bereich nur 3 * 5 Elemente hat.

    Wieso habe ich das nicht da schon gecheckt...


  • Mod

    HansKlaus schrieb:

    sicherlich. diese ganzen schutzmechanismen in anderen programmiersprachen nehmen einem irgendwie die sorgfaltspflicht ab, andererseits kann man gerade mit c/c++ wunderbar auf die hardware zugreifen und unglaublich effiziente programme schreiben.

    ich wollte mich jetzt auch nicht großartig streiten.

    Naja. Eine der hier auftretenden Parteien hat halt mit ihrer Aussage Recht, die andere nicht. Welche der Seiten Recht hat, bedarf auch keiner großen Diskussion über für und wider, da es mit dem Sprachstandard eine zentrale Autorität gibt, die die Frage eindeutig klärt, egal ob einem die Antwort gefällt oder nicht. Die Falschaussage sollte dann auch korrigiert werden, sowohl für andere Leser als auch den Autor der Falschaussage. Wobei dies zugegebenermaßen auf höflichere Art hätte erfolgen können/sollen.



  • trotzdem solltest du dir für die zukunft angewöhnen, klar verständliche variablennamen zu verwenden. es macht wenig spaß, erstmal überlegen, was h1, h2, h3 usw ist oder sein könnte. so sachen wie

    const int anzahlzeilen=10; //alternativ #define ANZAHLSPALTEN 10
    const int anzahlspalten=10; //alternativ #define ANZAHLZEILEN 10
    
    int main()
    {
    int matrix[anzahlzeilen][anzahlspalten]; //alternativ int matrix[ANZAHLZEILEN][ANZAHLSPALTEN];
    }
    

    machen den code deutlich lesbarer, rauben dem späteren programm aber keine zeit.



  • trotzdem solltest du dir für die zukunft angewöhnen, klar verständliche variablennamen zu verwenden. es macht wenig spaß, erstmal überlegen, was h1, h2, h3 usw ist oder sein könnte. so sachen wie
    

    Hast du vollkommen Recht. werde ich mir zu Herzen nehmen.
    Ihr werdet zwar darüber lachen, aber das war mit Abstand das längste Programm was ich je geschrieben habe.
    Ich denke, die geringe Komplexität bisher hat mich glauben lassen, dass das so in Ordnung geht.



  • HansKlaus schrieb:

    const int anzahlzeilen=10; //alternativ #define ANZAHLSPALTEN 10
    const int anzahlspalten=10; //alternativ #define ANZAHLZEILEN 10
    
    int main()
    {
    int matrix[anzahlzeilen][anzahlspalten]; //alternativ int matrix[ANZAHLZEILEN][ANZAHLSPALTEN];
    }
    

    Das ist KEINE Alternative, das ist was grundsätzlich Unterschiedliches.
    Du hast keine Ahnung, was du hier erzählst; liebe Kinder, sowas NICHT nachmachen.
    Du hast keine Ahnung von C und plapperst nur das dir im Erstsemester infiltrierte Halbwissen verständnislos nach.



  • Der Rückgabewert von multiplikation ist, so wie er gerade ist, überflüssig.
    Das ist nur der Wert von ergebnis[0][0].

    Besser wäre ein 0 für erfolgreich und ein anderer Wert, wenn du nicht multiplizieren kannst.

    Bei %i erkennt scanf die BAsis der Zahl. Du kannst da auch Hexadezimal- oder Oktalzahlen eingeben.
    Gerade Oktalzahlen machen da meist Probleme, da diese mit eine führenden Null beginnen.
    Also 0178 ist 1510 und 08 ist nicht definiert, da 8 nicht zu den Oktalziffern gehört.



  • Besser wäre ein 0 für erfolgreich und ein anderer Wert, wenn du nicht multiplizieren kannst.

    Das habe ich ja schon in Zeile 32 ausgeschlossen


  • Mod

    Broetchen93 schrieb:

    Besser wäre ein 0 für erfolgreich und ein anderer Wert, wenn du nicht multiplizieren kannst.

    Das habe ich ja schon in Zeile 32 ausgeschlossen

    Und was ist, wenn der Nutzer der Funktion nicht so voraussehend ist wie du in deinem eigenem Beispiel? DirkB hat schon Recht, derzeit macht der Rückgabewert gar nichts sinnvolles, dann kannst du ihn auch ganz weglassen, anstatt irgendeine Pseudoinformation vorzutäuschen. Aber eine Funktion, bei der der Nutzer erst selber Prüfungen auf Korrektheit der Argumente durchführen muss, ist keine gute Idee.



  • Ihr habt ja Recht und ich bedanke mich für den Hinweis, aber das war nicht unbedingt Sinn dieser Aufgabe.
    Dann könnte ich ja auch gleich noch nen ganzen Katalog mit Fehlercodes, die ausgegeben werden, hineinfügen, wäre aber in diesem Fall nicht Sinn der Sache.
    Allgemein gesprochen stimmen eure Aussagen natürlich



  • Wutz schrieb:

    Das ist KEINE Alternative, das ist was grundsätzlich Unterschiedliches.
    Du hast keine Ahnung, was du hier erzählst; liebe Kinder, sowas NICHT nachmachen.
    Du hast keine Ahnung von C und plapperst nur das dir im Erstsemester infiltrierte Halbwissen verständnislos nach.

    Begründung?


  • Mod

    HansKlaus schrieb:

    Begründung?

    Das was du gezeigt hast, gilt nur in C++. In C sind const int s keine Compilezeitkonstanten. Falls das bei dir funktioniert hat, dann benutzt du entweder einen C++-Compiler für deinen Code (ganz schlecht) oder unwissentlich ein inzwischen optionales Feature aus C99, das für diesen Zweck nicht gedacht ist (auch schlecht). Jedenfalls wäre im Fall mit den const int das Ergebnis ein variables Array, dessen Größe zur Laufzeit bestimmt wird, beim Fall mit den defines ein statisches Array, wie man es kennt. Zwei ganz unterschiedliche Dinge.



  • also ich habs eben durch den gcc geschickt, hat er ohne zu murren genommen, sowohl mit gcc main.c als auch mit gcc -x c main.c, es gibt keine Warnungen, keine Fehler, keine Speicherzugriffsverletzungen. 🙄



  • ich hab jetzt verstanden, was du meinst. die einen regen sich über einmalig 3 takte rechenzeitverlust auf, die anderen nicht. 😃

    aber wieso optimiert der compiler das nicht raus?



  • HansKlaus schrieb:

    also ich habs eben durch den gcc geschickt,

    Was hast du gejagt? Deinen 6-Zeiler ohne Code?

    HansKlaus schrieb:

    hat er ohne zu murren genommen, sowohl mit gcc main.c als auch mit gcc -x c main.c, es gibt keine Warnungen, keine Fehler, keine Speicherzugriffsverletzungen. 🙄

    Das -x c hat keinen Effekt, da du ja eine .c Datei hast.

    Aber -Wall und -std:c89 oder -std:c99 wären eine Option.



  • #include <stdio.h>
    
    const int zeilen=5;
    const int spalten=6;
    
    int main()
    {
    	int matrix[zeilen][spalten];
    	int i=0;
    	int j=0;
    	int zahl=0;
    
    	for(i=0;i<zeilen;i++)
    	{
    		for(j=0;j<spalten;j++)
    		{
    			matrix[i][j]=zahl;
    			zahl++;
    		}
    	}
    
    	for(i=0;i<zeilen;i++)
    	{
    		for(j=0;j<spalten;j++)
    		{
    			printf("%3d",matrix[i][j]);
    		}
    		printf("\n");
    	}
    
    	return 0;
    }
    

    lese- und schreibzugriff auf den speicher. keine Compilermeldungen, weder mit -std=c89 noch mit std=c99.



  • Du hast nicht nur keine Ahnung von C sondern auch keine Ahnung vom Compiler.
    Deine Implizierung, "Compiler läuft durch, also funktioniert das Programm und enthält keine Fehler" ist nur Ausdruck deines dümmlich-naiven Horizonts.
    Solche pubertären Deppen wie du kommen hier (leider) regelmäßig zu Wort, das Schema ist immer das Gleiche: mit irgendwo aufgeschnapptem Halbwissen plappern sie rum, machen gar Annahmen, warum die C Erfinder das so festgelegt haben, pauschalisieren ihre deppenhaften Vorstellungen schnell als "allgemeingültig", treffen Annahmen, warum das in C so und nicht anders funktioniert weil der Compiler keine (ihnen begreifliche) Fehler wirft.
    Du hast keine Ahnung von C.
    Das wird auch nicht besser, wenn du ständig deine Infiltrierungen deines Profs und Schrottcode wiederholst.
    Wenn du mal 25 Jahre professionelle C Erfahrung hast, kannst du dich hier mal wieder melden (und wirst über deine jetzigen sinnfreien, naiv-stümperhaften Aussagen nur den Kopf schütteln und einsehen, es wäre besser gewesen, sie nie gemacht zu haben).
    Also:
    Klappe halten, wenn man keine Ahnung hat. Und du hast keine Ahnung.


  • Mod

    *Seufz*

    Für etwas, das man einfach fix in jedem guten C-Lehrbuch nachlesen könnte, hältst du gewaltig lange an deinen Fehlvorstellungen fest.

    Beispielcode:

    #include <stdio.h>
    
    const int zeilen=5;
    const int spalten=6;
    
    int main()
    {
        int matrix[zeilen][spalten]; 
        return 0;
    }
    

    GCC mit C89, pedantic:

    test.c:8:5: warning: ISO C90 forbids variable length array 'matrix' [-Wvla]
         int matrix[zeilen][spalten]; 
         ^
    test.c:8:5: warning: ISO C90 forbids variable length array 'matrix' [-Wvla]
    test.c:8:9: warning: unused variable 'matrix' [-Wunused-variable]
         int matrix[zeilen][spalten]; 
             ^
    

    Dies ist, was dir ein anderer Compiler als Meldung geben könnte (und wird).

    Mit C99 wird Maschinencode erzeugt (ohne Optimierung, da sonst das unbenutzte Array entfernt würde):

    .file	"test.c"
    	.globl	zeilen
    	.section	.rodata
    	.align 4
    	.type	zeilen, @object
    	.size	zeilen, 4
    zeilen:
    	.long	5
    	.globl	spalten
    	.align 4
    	.type	spalten, @object
    	.size	spalten, 4
    spalten:
    	.long	6
    	.text
    	.globl	main
    	.type	main, @function
    main:
    .LFB0:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	pushq	%r14
    	pushq	%r13
    	pushq	%r12
    	pushq	%rbx
    	subq	$32, %rsp
    	.cfi_offset 14, -24
    	.cfi_offset 13, -32
    	.cfi_offset 12, -40
    	.cfi_offset 3, -48
    	movq	%rsp, %r10
    	movq	%r10, %r12
    	movl	$6, %r10d
    	movslq	%r10d, %r10
    	subq	$1, %r10
    	movq	%r10, -56(%rbp)
    	movl	$6, %r10d
    	movslq	%r10d, %r10
    	movq	%r10, %r13
    	movl	$0, %r14d
    	movl	$5, %r10d
    	movslq	%r10d, %r10
    	subq	$1, %r10
    	movq	%r10, -48(%rbp)
    	movl	$6, %r10d
    	movslq	%r10d, %r10
    	movq	%r10, %r8
    	movl	$0, %r9d
    	movl	$5, %r10d
    	movslq	%r10d, %r10
    	movq	%r10, %rax
    	movl	$0, %edx
    	movq	%r9, %r11
    	imulq	%rax, %r11
    	movq	%rdx, %r10
    	imulq	%r8, %r10
    	addq	%r11, %r10
    	mulq	%r8
    	leaq	(%r10,%rdx), %r8
    	movq	%r8, %rdx
    	movl	$6, %eax
    	cltq
    	movq	%rax, %rsi
    	movl	$0, %edi
    	movl	$5, %eax
    	cltq
    	movq	%rax, %rcx
    	movl	$0, %ebx
    	movq	%rdi, %rdx
    	imulq	%rcx, %rdx
    	movq	%rbx, %rax
    	imulq	%rsi, %rax
    	leaq	(%rdx,%rax), %r8
    	movq	%rsi, %rax
    	mulq	%rcx
    	leaq	(%r8,%rdx), %rcx
    	movq	%rcx, %rdx
    	movl	$6, %eax
    	movslq	%eax, %rdx
    	movl	$5, %eax
    	cltq
    	imulq	%rdx, %rax
    	salq	$2, %rax
    	leaq	3(%rax), %rdx
    	movl	$16, %eax
    	subq	$1, %rax
    	addq	%rdx, %rax
    	movl	$16, %edi
    	movl	$0, %edx
    	divq	%rdi
    	imulq	$16, %rax, %rax
    	subq	%rax, %rsp
    	movq	%rsp, %rax
    	addq	$3, %rax
    	shrq	$2, %rax
    	salq	$2, %rax
    	movq	%rax, -40(%rbp)
    	movl	$0, %eax
    	movq	%r12, %rsp
    	leaq	-32(%rbp), %rsp
    	popq	%rbx
    	popq	%r12
    	popq	%r13
    	popq	%r14
    	popq	%rbp
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE0:
    	.size	main, .-main
    	.ident	"GCC: (geht niemanden hier etwas an)"
    	.section	.note.GNU-stack,"",@progbits
    

    Hingegen mit defines (egal ob C89 oder C99):

    .file	"test.c"
    	.text
    	.globl	main
    	.type	main, @function
    main:
    .LFB0:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	subq	$8, %rsp
    	movl	$0, %eax
    	leave
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE0:
    	.size	main, .-main
    	.ident	"GCC: (geht niemanden hier etwas an)"
    	.section	.note.GNU-stack,"",@progbits
    

    Selbst wenn du kein Assembler verstehst, sollte offensichtlich sein, dass es hier riesige Unterschiede gibt. Im zweiten Compilat existieren die Objekte zeilen und spalten nicht mehr. Das kann man so wollen oder nicht; wichtig ist, dass es einen Unterschied macht.

    Viel wichtiger und auch viel größer ist jedoch der Unterschied bei der Speicherallokierung in der main. Die im zweiten Fall ebenfalls nicht wirklich existiert, da es sich einfach nur um einen Offset beim Start der Funktion handelt. Beim ersten Code muss hingegen richtig Arbeit verrichtet werden (und zwar weit mehr als 3 Takte), da es sich um eine (semi-)dynamische Allokation handelt.


Anmelden zum Antworten