Välkommen till linuxportalen.se!

Linuxportalen.se är Sveriges största och aktivaste webbplats för användare av öppen- och fri programvara.

Du besöker Linuxportalen.se som gäst vilket begränsar din möjlighet att använda webbplatsens alla funktioner. Genom att registera dig som medlem får du inte bara möjlighet att söka bland webbplatsens innehåll, skapa nya och delta i befintliga diskussioner, skapa din egen blogg, kommunicera med andra medlemmar genom privata meddelanden och delta i omröstningar. Du får också tillgång till Veckans Kadavro - en seriestrip unikt skapad för Linuxportalen.se!

Registeringen sker snabbt och är helt kostnadsfri - tveka inte, bli medlem idag!

multidimensionell array till funktion

Jag har en multidimensionell array som jag ska skicka över till en funktion som skriver ut den.
Programmet ser ut så här

#include <stdio.h>
...

void outString(char *string);

int main() {
char string[200][0];
scanf("%200s",string);
outString(string);

return 0;
}

void outString(char *string) {

printf("%s\n", string);

}

sen så får jag det här felet:


chararrayfunc.c: In function 'main':
chararrayfunc.c:10: warning: passing argument 1 of 'outString' from incompatible pointer type

Hur ska jag göra för att få över arrayen till funktionen "outString"?
Det fungerade fint när string deklarerades som char string[200];

PS. Det här är bara en tanke till en kod till ett större program, då jag vet att jag och alla här inne kan säkert komma på en mängd bättre sätt att skriva ut en scanf'ad sträng ;P

Alternativ för kommentarvisning

Välj ditt önskade sätt att visa kommentarerna och klicka på "Spara" för att verkställa dina ändringar.

uffe_nordholms bild

Vad har du för nytta av en array med char, där du har 200 element med längd noll?

netbears bild

Funktionen outString tar ingen multidim-array. Pröva med nedanstående istället. Tänk på att "printf("%s\n", string);" inte heller förväntar sig en multidimensionel-array.

void outString(char **string) {

Och ja en array med 200*0 element doesn't make sense.

-------------------------------------------
Björn (netbear)
Numbers don't lie, people do.

------------------------------------------- Björn (netbear) Numbers don't lie, people do.

alberts bild

Du har inte fått till det där med en array av strängar riktigt. Om du tex vill ha fem strängar av (max) längd 200 tecken så skriv:

char string[5][200];

För att läsa in data till första strängen, skriv:

scanf("%200s",string[0]);

och när du ska anropa outString, skriv

outString(string[0]);

för att skriva ut första strängen. Andra strängen är string[1] osv. Då behöver du inte typecasta heller.
 
Det som kommer hända med ditt program så som du skrev det först, är att scanf kommer läsa in data över hela string, och vidare över den sparade framepointern (%ebp) och vidare kommer returadressen skrivas över och när programmet returnerar från main kommer %eip få helt fel värde och det kommer troligen resultera i en segmentation fault. Inte riktigt som det var tänkt Wink
 
En liten detalj som man ofta missar är också att man tror att det ska finnas plats för 200 tecken om man har en array [200] och skriver scanf(%200s,...). Men det gör det inte. Det finns bara plats för 199 tecken, det sista tecknet är en nolla som avslutar strängen. Om du matar in 200 tecken och bara har en enda sträng i arrayen så blir det en segmentation fault, orsakad av en så kallad "off by one" error. Alltså borde det stå

scanf("%199s",string[0]);

för att allt ska funka klockrent.

alberts bild

Sista svaret blev lite förvirrat. För att göra det lite tydligare kommer koden istället:

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

void outString(char **string)
{
   int i = 0;
   while (string[i] != NULL) {
      printf("%s\n", string[i]);
      i++;
   }
}

int main(void)
{
   int i;
   char *string[5];

   for (i = 0; i < 4; i++) {
      string[i] = malloc(200);
      string[i][0] = '\x0';
   }
   string[4] = NULL;
   scanf("%199s", string[0]);
   outString(string);
   for (i = 0; i < 4; i++) {
      free(string[i]);
   }

   return 0;
}

Notera hur sista pekaren, string[4], sätts till NULL. Det enda du behöver lägga till är en kontroll om anropet till malloc gick bra eller ej (den returnerar NULL om det inte gick bra).

misiu_mps bild

Eftersom tvådimensionella vektorer implementeras som pekare till pekare är det okej att ta emot dessa som (TYP**), men det är mycket bättre om man kan ange syftet med argumentet genom att faktiskt deklarera den som en vektor (kräver c99):

<pre>
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;memory.h&gt;
// v deklareras som en tvådimensionell vektor av variabel storlek
// de variabel som anger storleken måste deklareras före vektorn
void out(int r, int c, int v[r][c]){
int i,j;
for (i = 0; i&lt;r; ++i){
for ( j = 0; j&lt;c; ++j ){
printf("%d\t", v[i][j]);
}
printf("\n");
}
}

int main(){
       //här används en liten kul grej i c99: "designated initializer"
       //med den kan man initiera en del av vektorn genom att ange vilka idex som angivet data avser:
int v[4][3] =  { [2] = {1, 2, 3}, [3] =  {32, 23, 11} };

int v0[] = { 9, 8, 9,};
int v1[] = {6, 7, 8,};
memcpy(v[0], v0, 3*sizeof(int));
memcpy(v[1], v1, 3*sizeof(int));
out(4, 3, v);
return 0;
}
</pre>

turixs bild

i det större programmet jag skrev om kommer det självklart inte vara en array med 200 element/längd 0. utan det här är endast en prototyp

turixs bild

"och när du ska anropa outString, skriv

outString(string[0]);

"

men hur ska jag överföra hela strängarrayen till funktionen?
dvs funktionen ska ha tillgång till alla element

Kristians bild

Du får hemskt gärna lägga till detta eller liknande exempel i C-skolan i wikin Smile

----------------------------------
MÖLUG

---------------------------------------

 

uffe_nordholms bild

OK.
.
.
Vad händer om du typecastar string i anropet till outstring, sä det ser ut
outString((char*)string);

alberts bild

Det enklaste är att göra en for-loop och skicka en sträng i taget. Om du verkligen vill skicka en array av strängar som argument så får du ändra parametern i outString till char **string eller eventuellt char *string[]. Sen får du loopa inne i outString i stället. Men det är lite knepigt med "dubbelpekare" som det kallas. I anropet så skriver du outString(string); Eventuellt så klagar kompilatorn på att ** och [][] inte är samma sak. Men i det här fallet så är det (i stort sett) samma sak och du kan göra en typecast för att slippa kompileringsvarningen, outString((char**)string);. Ett problem du får är att du inte vet hur många strängar som skickas. Se till att skriva en nolla '\x0' först i alla strängar som inte används. Sen kanske du kan ha en #define eller en extra parameter för att tala om hur många strängar som finns i arrayen.
 
Ett vanligt sätt att lösa problemet med antalet strängar är att sätta den sista pekaren till NULL. Men det kan inte du göra eftersom du deklarerat arrayen som string[][]. För att sätta sista till NULL så måste du deklarera som char *string[] och sedan allokera minne till varje sträng med malloc. Fast det blir ju ännu mer komplicerat...

alberts bild

Oj vilket jobb du gjort Kristian! Det måste vara den bästa sidan på hela wikin. I alla fall för oss som håller på med C-programmering. Jag kan fylla på lite om barnen somnar tidigt i kväll.

alberts bild

Hej Kristian!

Nu lade jag in ett stycke om stränghantering i din C skola, dock ej arrayer av strängar, bara vanliga strängar. Redigera gärna stycket som du tycker passar.

turixs bild

tack uffe_nordholm!
Nu fungerade det!

Kristians bild

Tack Smile Grymt jobbat! Pedagogiskt och välskrivet (mycket bättre än jag själv)! Det finns många som kan C här på LP, men det är bara jag, min kursare Micke och nu du som hittils har bidragit till sidan. Var är ni andra? Har ni fått segfault hela bunten Wink ?

----------------------------------
MÖLUG

---------------------------------------