ubuntuusers.de

Zeiger auf mehrdimensionales char Array - in C

Status: Ungelöst | Ubuntu-Version: Ubuntu 12.04 (Precise Pangolin)
Antworten |

mgolbs

Anmeldungsdatum:
11. Januar 2009

Beiträge: 269

Wohnort: Tirschenreuth - Löbau

Hallo,

habe da ein für mich derzeit nicht lösbares Problem. 😕

Ich möchte "Stings" die in Zeilen unbekannter Anzahl, immer gleicher Längendefinition, untereinander stehen in ein Array überführen (per char Array ), wo ich per Zeiger (* oder **) darauf zugreifen kann und die Zeilen dann per qsort() sortiere. Bei einem Array z.B. int kein Problem **zeiger,... zeiger[i][j]... Wenn ich das gleiche per char **zeigerstring; mache kommt beim Sortieren nichts brauchbares raus. Der Zeiger (*) hat ja die Adresse des ersten Elements als Adresse, beim char Array den Wert[0]. Wenn ich sortieren will möchte ich ja nicht nur nach Inhalt des Zeichens in [0] sondern bis \0 sortieren und auch nicht nur das Element[0]. Mir fehlt irgend wie das Versändnis der Behandlung von Strings in char Array ab 2ter Dimension, vor allem wie ich nicht das einzelne Zeichen im Array anspreche, sondern die Zeichenkette bis jeweils \0 nutzen kann.

Ich gehe davon aus, dass wenn ich malloc() verwende, das Array von mehrdimensionalen char Arrays einfach im Speicher immer hintereinander weg geschrieben wird. Wenn ich eine feste Länge des 1D char Arrays[] Anteils im gesamten mehrdimensionalen Array vereinbart habe, könnte man einfach durch Zählen der Vielfachen und deren Länge irgend wie zugreifen... oder ist das Quatsch?

1
Code folgt.

Über Tipps, Infos, Links zu mehrdimensionalen, dynamischen char Arrays fester 1D char Arrays Anteile wäre ich sehr dankbar. Auch wie man das per Zeiger organisiert und per qsort anspricht. Habe schon Stunden Dokus, Anleitungen gelesen, programmiert und getestet.. komme aber durch Verständnisproblem nicht weiter.

Gruß Und Dank Markus

Dee Team-Icon

Avatar von Dee

Anmeldungsdatum:
9. Februar 2006

Beiträge: 20095

Wohnort: Schwabenländle

Erstmal ohne Erklärung:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// http://www.cplusplus.com/reference/cstdlib/qsort/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const int num = 4;
char* values[num] = { "Maus", "Katze", "Hund", "Elefant" };

int compare(const void *a, const void * b)
{
    // gefaehrlich, strncmp besser!
    return strcmp(*(char**)a,*(char**)b);
}

int main ()
{
    printf ("\nUnsortiert:\n");
    for (int n=0; n<num; n++)
    {
        printf ("%d: %s\n", n, values[n]);
    }
    
    qsort(values, num, sizeof(char*), compare);
    
    printf ("\nSortiert:\n");
    
    for (int n=0; n<num; n++)
    {
        printf ("%d: %s\n", n, values[n]);
    }
    
    return 0;
}

Wenn Du Fragen dazu hast, einfach fragen.

Gruß Dee

mgolbs

(Themenstarter)

Anmeldungsdatum:
11. Januar 2009

Beiträge: 269

Wohnort: Tirschenreuth - Löbau

Hallo,

vielen Dank. Das erklärt schon mal einiges.

1
char* values[num];

Ich versuche dies erst mal in meinem Programm umzusetzen. Danke für das Angebot mit den Fragen!

Vielen Dank und Gruß Markus

mgolbs

(Themenstarter)

Anmeldungsdatum:
11. Januar 2009

Beiträge: 269

Wohnort: Tirschenreuth - Löbau

Hallo,

zwei Fragen bezüglich des Ansatzes:

1
char* values[num];

habe ich noch.

Was ist der Unterschied zwischen:

1
char* values[num];

und

1
char *values[num]; // geht das überhaupt???

?

Wie kann ich ein malloc() auf values machen? So sicher nicht:?

1
values = (char *)malloc(num*sizeof(char*));

Gruß und Dank Markus

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Ganz generell: Für praktische Anwendungen nutze die Glib und deren Container! Damit ersparst Du Dir u.a. das Allozieren von Speicher und hast darüber hinaus eine Menge Algorithmen eingebaut, die Du nicht zum x. Mal selber implementieren musst ☺

Zum Lernen kann man sich Arrays natürlich angucken ☺

Bei produktiven Programmen kommt man um die Glib im C-Umfeld imho nicht herum 😉

mgolbs

(Themenstarter)

Anmeldungsdatum:
11. Januar 2009

Beiträge: 269

Wohnort: Tirschenreuth - Löbau

Hallo,

vielen Dank für die Antwort. Leider ist bei mir die Softwareentwicklung nur ein Werkzeug, wo ich weder Fachmann bin, noch die notwendige Zeit wirklich da ist. 😳 Funktionalität muss stimmen und man gibt sich Mühe so weit es halt geht...

Der Hinweis mit der glib ist wirklich gut. Ich habe mit der glib auch Konflikte, wenn ich am Ende meines Code free() für zwei Zeiger auf Arrays verwende.... Es wird wohl auf Sicht nichts anderes übrig bleiben als glib zu nutzen. Leider sind dann die Programme wohl nicht mehr plattformunabhängig?

Habe nun auch festgestellt, dass:

1
2
3
char* values[num];
und
char *values[num];

das gleiche ist. Nur habe ich bis jetzt immer die Schweibweise *values verwendet.

Gruß und Dank Markus

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

mgolbs schrieb:

Es wird wohl auf Sicht nichts anderes übrig bleiben als glib zu nutzen. Leider sind dann die Programme wohl nicht mehr plattformunabhängig?

Wieso? Die Glib ist doch auf vielen Plattformen verfügbar - oder fehlt Dir da eine, die Du berücksichtigen musst?

mgolbs

(Themenstarter)

Anmeldungsdatum:
11. Januar 2009

Beiträge: 269

Wohnort: Tirschenreuth - Löbau

Hallo,

wieder was dazu gelernt. Glib klang für mich immer nach Linux. Ich bräuchte die Programme eventuell, und dies nur theoretisch, für win64.

Gruß und Dank Markus

Dee Team-Icon

Avatar von Dee

Anmeldungsdatum:
9. Februar 2006

Beiträge: 20095

Wohnort: Schwabenländle

Was ist der Unterschied zwischen "char* values[num];" und "char *values[num];"

Antwort: Die Position des Sternchens. *g* Im Ernst: Gibt keinen. Ich versuche es syntaktisch immer zusammenzufassen. Das heißt "char* values[num]" sagt mir, ich habe ein Array values der Größe num und der Inhalt sind Zeiger auf Chars. Das liest sich für mich einfach nur leichter. (Vor allem, weil man beim Dereferenzieren ja den Stern an den Wert stellt, verwirrt das eher.)

Wie kann ich ein malloc() auf values machen?

Gar nicht bzw. in meinen Augen nicht sauber. Du könntest zwar den Speicher mit malloc in der richtigen Größe allokieren und dem Array unterschieben, aber sauber ist es, jeden Wert einzeln zu allokieren. Zumal es ja auch nicht notwendig ist. Den Speicher für die num * char-Zeiger hast Du ja schon durch das C-Array. Die fehlt ja nur der Speicher für die char* selbst. Die solltest du dann auch einzeln allokieren.

Ich selbst versuche im Übrigen auch, wenn möglich, nur die Standardlibs zu nutzen, sodass ich nichts extra dazulinken muss, wenn die Plattform sich ändert. Aber ich programmiere auch kein C mehr. *g*

Gruß Dee

mgolbs

(Themenstarter)

Anmeldungsdatum:
11. Januar 2009

Beiträge: 269

Wohnort: Tirschenreuth - Löbau

Hallo,

danke für die Antwort und die Tipps. Jede Zelle für sich habe ich schon mal probiert, bin aber beim Ansprechen der einzelnen "Wörter" (Strings) über das char Array gescheitert.

Es sollen zwei Arrays entstehen die per Zeiger anzusprechen sind. Beim 2D float Array klappt das.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
#---------------------------------------------------------------------------------------
#	Author: mgolbs
#---------------------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h> /* timeval */
#include <sys/socket.h> /* select() */
#include <unistd.h>
#include <math.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include  <inttypes.h>
#include <sys/mman.h>
#define clrscr() printf("x1B[2J")


#define Zeilen 20000000
#define Spaltenchar 200
#define Spaltentensor 13
float **pfloatp = NULL;
char **pcharp = NULL;
long i1, Zaehler2;
 
// gcc -m64 -ansi -std=c99 -g -Wall -Wextra -pedantic-errors unbekannt.c -o unbekannt -lm */
 
int main(int Anzahlargumente, char **argumentenvektor){

pfloatp = (float **)malloc(Zeilen*sizeof(float*));

for(i1=0;i1<Zeilen;i1++){
	if((pfloatp[i1] = (float *)malloc(Spaltentensor*sizeof(float))) == NULL){
		printf("Fehler: malloc fehlgeschlagen!\n");
		exit(0);
	}
}
if( pfloatp==NULL){
	printf("Speicherfreigabe 1 fehlgeschlagen");
}
pcharp = (char **)malloc(Spaltenchar*sizeof(char*));
	
for(i1=0;i1<Spaltenchar;i1++){
	if((pcharp[i1] = (char*)malloc(Zeilen*sizeof(char))) == NULL){
		printf("Fehler: malloc fehlgeschlagen!\n");
		exit(0);
	}
}

pcharp = malloc(Zeilen*Spaltenchar*sizeof(char)); 
printf("Zeigeradresse von pfloatp %p \n",&pcharp);

//...
//...
//...

qsort(pcharp,Zaehler2,Spaltenchar*sizeof(char),(int (*) (const void*, const void*))strcmp);

//...
//...
//...

for(i1=0;i1<Zeilen;i1++){
	free(pfloatp[i1]);
	}
for(i1=0;i1<Zeilen;i1++){
	free(pcharp[i1]);
	}
pfloatp = NULL;
pcharp = NULL;

return EXIT_SUCCESS;
}

Wie kann ich jeweils eine Zeile des char Array ansprechen, also den String bis \0?

1
2
(*pcharp)[1] // Zeile 0 char Zeichen 1??
*pcharp[1] // Zeile 1 char Zeichen 0??

Über Tipps und Infos wäre ich sehr dankbar.

Gruß und Dank Markus

Dee Team-Icon

Avatar von Dee

Anmeldungsdatum:
9. Februar 2006

Beiträge: 20095

Wohnort: Schwabenländle

Also gehen wir das mal Zeile für Zeile durch:

#define Spaltenchar 200
char **pcharp = (char **)malloc(Spaltenchar*sizeof(char*));

Du allokierst insgesamt Speicher für 200 * Größe eines char-Zeigers. Effektiv hättest du auch einen float- oder void-Zeiger nehmen können, da alle Zeiger gleich groß sind, normalerweise 4 Byte. Du hast also somit 800 Byte allokiert und wandelst das nach char** um.

Du hast also einen Zeiger auf ein Speicherbereich, der wiederum Zeiger enthält und zwar 200 Stück.

long i1;
for(i1=0;i1<Spaltenchar;i1++){
    if((pcharp[i1] = (char*)malloc(Zeilen*sizeof(char))) == NULL){

Sowas gehört in meinen Augen verboten und ich hasse es, dass C sowas zulässt. Es verbessert das Verständnis nämlich nicht, wenn Du Zuweisung und Vergleich gleichzeitig machst. Daher:

#define Zeilen 20000000
long i1;
for( i1 = 0; i1 < Spaltenchar; i1++ ) {
    pcharp[i1] = (char*)malloc(Zeilen*sizeof(char));
    if ( pcharp[i1] ) {
    	printf("Fehler: malloc fehlgeschlagen!\n");
        exit(0);
    }
}

pcharp war ein Zeiger auf einen Speicherbereich, indem wieder Zeiger liegen. pcharp[0] zeigt Dir also auf den ersten char-Zeiger. pcharp[1] auf den zweiten etc. Du allokierst also mit der Schleife für Deine 200 char-zeiger jeweils 20000000 Zeichen.

Passt also alles!

pcharp = malloc(Zeilen*Spaltenchar*sizeof(char)); 
printf("Zeigeradresse von pfloatp %p \n",&pcharp);

Wieso Du das danach machst, habe ich nicht verstanden, zumal die printf-Ausgabe nicht dazu passt. Jedenfalls vernichtest Du die zuvor aufgebauten Zeiger in pcharp alle wieder.

Gehen wir weiter und überspringen das qsort, was nicht wirklich gut ist mit dem Missbrauch von strcmp:

for(i1=0;i1<Zeilen;i1++){
    free(pcharp[i1]);
}

Du gibst hier also 20000000 Elemente frei ... Hm, Moment, Du hattest doch nur 200 angelegt. Genau: Du hast nur "Spaltenchar" Elemente mit alloc angelegt, gibst aber "Zeilen" Elemente frei. Kein Wunder, dass Du hier abstürzt, weil Du viel zu weit iterierst und Speicher freigibst, der Dir gar nicht gehört.

pcharp = NULL;

Und damit hast Du ein Speicherleck. Du wolltest mit der Schleife oben zwar den Speicher freigeben für das "pcharp[i1] = malloc...", aber den Speicher für das "char **pcharp = malloc" hast Du nicht mehr freigegeben.

Gruß Dee

PS: Und mach Dir mal Gedanken über Dein Typsystem. Du mischt recht willkürliches defines, die eigentlich Konstanten sind, mit long.

PPS: Muss das eigentlich so dynamisch sein oder stehen die Werte für Zeilen und Spalten wirklich schon vorher fest? Dann müsstest Du rein gar nichts dynamisch anlegen.

Antworten |