[Powered by Google Translate] Låt oss tala om structs. Structs ger oss ett sätt att gruppera ett gäng variabler tillsammans till en trevlig paket. Det är nog enklast att se ett exempel på en gång, så vi säger struct, sedan öppna klammerparentes, och i denna struct, vi har en int ålder, en char * namn, och det är det. Det kan tyckas konstigt med ett semikolon efter en klammerparentes, men det är i själva verket nödvändigt med structs. Ett giltigt typ kan gå i struct definition. Här har vi använt en int och char *, men du kan även använda en rad av säga, 100 delar eller med en annan strukt. När du använder structs i C, du skapar nya typer ur en samling av andra typer. Här gör vi en ny typ ur ett heltal och en char *. Som vi kommer att se senare, en struct typ är på många sätt motsvarar någon annan typ du är van vid. Vanligtvis kommer jag att jämföra hur en struct typ liknar ett heltal typ. Medan koden vi skrev är giltig C, det är inte mycket användbart, och klang kommer att ge oss en varning. Kom ihåg hur structs och dess liknar? Tja, vi i princip bara sagt int, vilket inte är en mycket hjälpsam linje. Så låt oss faktiskt deklarera en variabel av detta slag genom att ge den ett namn innan semikolon. Vi ringer variabeln eleven. Nu har vi deklarerat en variabel kallad elev med den typ som ges av struct. Hur får vi till variablerna inne i struct? Tekniskt namn för dessa variabler är medlemmar. För att komma åt en viss medlem i en student struct, du lägger en punkt till variabelnamnet, följt av namnet på den medlem du vill ha. Så här, bara 2 giltiga möjligheter är student.age och student.name. Och vi kan göra något liknande student.age = 12 och student.name = student. Nu vad om vi ville göra en andra elev? Du kanske tror att kopiera och klistra dessa rader och ändra elev till elev 2 eller något, och det kommer att fungera, men tekniskt, student och student 2 har inte samma typ. Se, kommer du inte att kunna tilldela dem till varandra. Detta beror hittills din struct har anonym. Vi måste ge den ett namn. För att göra det sätter vi namnet på struct efter ordet struct. studerande, följt av definitionen. Vi kan fortfarande omedelbart deklarera en variabel av typen struct elev, som vi gjorde förr. Vi kallar det S1 Genom att ge struct ett namn, Vi kan nu använda struct elev i nästan exakt samma sätt som vi skulle använda int. Så vi kan deklarera en variabel av typen struct student, som struct studerande S2. Liksom arrayer, structs ger en syntax genväg initiering, så vi kan säga, Struct elev S2 lika vänster klammerparentes 3, S2. Här kommer S2.age vara 3, och S2.name kommer att peka på S2. Tänk på alla de saker du kan göra med en int typ och de flesta av dem kan du göra med en struct elev typ. Vi kan använda en struct elev som en typ av funktion parameter. Vi kan använda struct elev inne i en ny struktur. Vi kan ha en pekare till en struct elev. Vi kan göra stor struct student. Struct student är en typ precis som int är en typ. Vi kan också tilldela S1 till S2 eftersom båda är av samma typ, så att vi kan göra S1 = S2. Vad händer om vi gör S1.age = 10? Har S2 förändring alls? Återigen, tänk på structs precis som vanliga heltal. Om vi ​​tilldelar några int X till någon int Y, som X = Y och sedan ändra X, som i X + +, ändrar Y alls? Y ändras inte här, och så inte heller S2 ovan. S2.age är fortfarande 3. Men observera att när du tilldelar en struct till en annan, alla pekare pekar fortfarande på samma sak, eftersom de var bara kopierade. Om du inte vill att pekarna att delas, måste du manuellt hantera det, kanske genom malicking ett block av minne för en av pekarna för att peka på och kopiera data över. Det kan vara irriterande att behöva skriva struct elev överallt. Med hjälp av en typ def, kan vi göra typ def struct och vi kommer att kalla det student. Nu kan vi använda elev överallt som vi brukade använda struct student. Denna typ def är en anonym struktur och kallar det student. Men om vi håller också studenten identifierare bredvid ordet struct, såsom i typedef struct elev, vi kunde använda både struct elev och elev omväxlande nu. De behöver inte ens ha samma namn. Vi kunde skriva def struct elev till Bob och sedan struct student och Bob skulle vara utbytbara typer. Oavsett vilken typ def, Vi behöver identifieraren bredvid Struct Om definitionen av struct är rekursiv. Till exempel, typ def struct nod och det kommer att definieras som en int val och det kommer att ha en pekare som pekar på en annan struct nod., som i struct nod * nästa. Och sedan kommer vi kalla det nod. Denna struktur är rekursiv, eftersom definitionen av struct nod ingår en en pekare till en struct nod. Observera att vi har att säga struct nod * nästa insidan av definitionen av struct noden, eftersom typen def inte har avslutat ännu att tillåta oss att förenkla detta bara nod * nästa. Du får lära dig mer om structs liknar detta när man hanterar länkade listor och träd. Vad sägs om structs i en funktion? Detta är också helt giltigt. Vi kunde ha ogiltig funktion som tar som argument, studerandes s och gör något med den studerande. Och då kan vi skicka det som student struct som så. Func av S1 från tidigare. Den struktur beter precis som ett heltal skulle då skickas till en funktion. Func får en kopia av S1 och så kan inte ändra S1; snarare bara en kopia av det som lagras i S. Om du vill att funktionen ska kunna ändra S1, FUNC kommer att behöva ta en student * S och du måste passera S1 efter adress, som så. Student * S FUNC & S1. Det finns ytterligare en anledning att gå efter adress här. Vad händer om vår struct innehöll 100 fält? Varje gång vi passerar en elev att funk, vårt program måste kopiera alla dessa 100 områden i funk argument S, även om det använder aldrig den stora majoriteten av dem. Så även om funk inte planerar att ändra den studerande, Om ändå vara värdefullt att passera efter adress. Okej, vad händer om vi vill skapa en pekare till en struct? Vi kan göra något liknande Studenten * S lika malloc storlek elev. Observera att storleken på fortfarande fungerar här. Så hur åt vi en ålder ledamot av blocket att S pekar på? Du kanske först tänker göra * S.age = 4, men detta kommer inte att helt att fungera. Eftersom detta kommer verkligen tolkas som * S.age inom parentes = 4, som inte ens går att kompilera, eftersom S är inte en struct eller snarare en pekare till en struct, och så pricken kommer inte att fungera här. Vi kan göra (* S). Ålder = 4 men parenteserna kan få irriterande och förvirrande. Tack och lov har vi en speciell pil operatör som ser ut ungefär så S-> ålder = 4. Dessa 2 sätt referera ålder är likvärdiga och vi egentligen inte någonsin behöver pilen operatör, men det gör saker och ting ser trevligare. Eftersom S är en pekare till en viss minnesblock som innehåller struct, du kan tänka S> ålder som följer pekaren pil och ta tag i åldern medlem. Så varför ska vi använda någonsin structs? Det är definitivt möjligt att komma undan med bara primitiva heltal, tecken, pekare och liknande att vi är vana vid, istället för S1 och S2 innan, vi kunde ha haft Ålder1, age2, NAME1 och NAME2 alla på separata variabler. Detta är bra med bara 2 studenter, men vad händer om vi hade 10 av dem? Och vad händer om i stället för att bara 2 fält, studenten struct hade 100 områden? GPA, kurser, hårfärg, kön och så vidare. Istället för att bara 10 structs behöver vi 1.000 olika variabler. Också överväga en funktion som tar det struct med 100 fält med enda argument och skriver i alla fält. Om vi ​​inte använder en struct, varenda gång vi kallar den funktionen, Vi behöver skicka vid alla 100 variabler, och om vi har 100 variabler för studerande 1, och 100 variabler för studerande 2, Vi måste vara säkra på att vi inte råkar passera vissa variabler från student 1 och några variabler från elev 2. Det är omöjligt att göra det misstaget med en struktur, eftersom alla 100 variabler finns i ett enda paket. Bara ett par slutliga anteckningar: Om du har förstått allt fram till denna punkt, stor. Resten av videon är bara för fullständighetens skull. Eftersom structs kan hålla alla typer av pekare, De kan också hålla funktionspekare. Om du är bekant med objektorienterad programmering, detta är ett sätt att använda structs att programmera i ett objektorienterat stil. Mer om funktionspekare vid ett annat tillfälle. Dessutom, ibland kan du ha två structs vars definitioner är beroende av varandra. Till exempel, vi kunde ha struct A, vilken definieras som en pekare till en struct B, struct B * X, och nu kan vi ha en struct B som definieras som en pekare till en struktur A, struct A * Y. Men detta kommer inte att kompilera, eftersom struct B inte finns vid den tidpunkt som struct A sammanställs. Och om vi byter struct A och struct B, då skulle vi bara vara kvar med samma problem, den här gången, med struktur A inte existerande. För att lösa detta, kan vi skriva struct B; innan definitionen av struktur A. Detta kallas en främre förklaring. Detta kan bara kompilatorn vet att struct B är en giltig typ som kommer att vara fullt definieras senare eller någon annanstans. Mitt namn är Rob Bowden, och detta är CS50. [CS50.TV]