[Powered by Google Translate] Vamos falar sobre estruturas.
Estruturas nos fornecer uma maneira de agrupar um monte de variáveis ​​juntas
em um bom pacote.
É provavelmente mais fácil para ver um exemplo de imediato,
por isso dizemos struct,
em seguida, uma chave de abertura,
e nessa estrutura, vamos ter uma idade int,
um nome de char *,
e é isso.
Pode parecer estranho com um ponto e vírgula depois de uma chaveta,
mas é, de facto, necessário, com estruturas.
Qualquer tipo válido pode ir dentro da definição de struct.
Aqui, nós usamos um int e um char *,
mas você também pode usar uma matriz, de, digamos, 100 elementos
ou mesmo struct outro.
Quando você está usando structs em C,
você está criando novos tipos
de uma coleção de outros tipos.
Aqui, nós estamos fazendo um novo tipo
de um inteiro e um char *.
Como veremos mais tarde, um tipo de estrutura
está em um monte de maneiras equivalentes a qualquer outro tipo que você está acostumado.
Normalmente, eu vou estar comparando como um tipo de estrutura
é semelhante a um tipo inteiro.
Enquanto o código que escreveu é válido C,
não é muito útil,
e bumbum vai nos dar um aviso.
Lembre-se como estruturas e os seus são semelhantes?
Bem, basicamente, apenas disse
int,
o que não é uma linha muito útil.
Então, vamos realmente declarar uma variável desse tipo
, dando-lhe um nome antes do ponto e vírgula.
Vamos chamar o estudante variável.
Agora que já declarou um estudante variável chamada
com o tipo de dado pela estrutura.
Como chegamos às variáveis ​​dentro da estrutura?
Tecnicamente, os nomes para essas variáveis
são membros.
Para acessar qualquer membro particular em uma estrutura de estudante,
você acrescentar um ponto para o nome da variável,
seguido do nome do membro que você deseja.
Então, aqui, as únicas duas possibilidades válidos
são student.age
e student.name.
E nós podemos fazer algo como
student.age = 12
e student.name = estudante.
Agora, o que se queria fazer um segundo aluno?
Você pode pensar que copiar e colar estas linhas
e mudar aluno para aluno dois ou algo assim,
e que irá trabalhar,
mas tecnicamente aluno e aluno 2
não têm o mesmo tipo.
Veja, você não será capaz de atribuí-los a um outro.
Isto é porque, até agora,
sua estrutura foi anônima.
Precisamos dar-lhe um nome.
Para fazer isso, insira o nome da struct
após a struct palavra.
estudante,
seguido pela definição.
Nós ainda podemos imediatamente declarar uma variável do tipo
struct aluno, como fizemos antes.
Vamos chamá-lo de S1
Ao dar a estrutura de um nome,
agora podemos usar estudante struct
em quase exatamente o mesmo que usaria int.
Assim, podemos declarar uma variável do tipo struct aluno,
como
struct aluno S2.
Como arrays, estruturas fornecem uma sintaxe de inicialização de atalho,
assim podemos dizer, struct aluno S2
é igual
esquerda encaracolados cinta 3, S2.
Aqui, S2.age será de 3,
e S2.name irá apontar para S2.
Pense em todas as coisas que você pode fazer com um tipo int
ea maioria deles você pode fazer com um tipo de estudante struct.
Podemos usar um estudante de estrutura como um tipo de um parâmetro de função.
Podemos usar struct aluno dentro de uma estrutura nova.
Podemos ter um ponteiro para um estudante struct.
Nós podemos fazer o tamanho de aluno struct.
Estudante struct é um tipo
como int é um tipo.
Podemos também atribuir S1 a S2
já que ambos são do mesmo tipo, para que possamos fazer
S1 = S2.
O que acontece se não fizermos
S1.age = 10?
Muda S2 em tudo?
Mais uma vez, acho que as estruturas apenas como inteiros regulares.
Se atribuirmos alguma X int a algum Y int,
como X = Y
e depois mudar X,
como em X + +,
Y não muda em nada?
Y não é alterado aqui, e assim também não S2 acima.
S2.age ainda é 3.
Mas note-se que, quando a atribuição de uma estrutura para outra,
todos os ponteiros ainda apontam para a mesma coisa,
vez que só foram copiados.
Se você não quer que os ponteiros para ser compartilhado,
você terá que lidar com isso manualmente,
talvez por malicking um bloco de memória para um dos ponteiros para apontar para
e copiar os dados mais.
Pode ser chato ter que escrever struct aluno em todos os lugares.
Usando um def tipo, podemos fazer
Tipo de def
struct
e vamos chamá-lo de estudante.
Agora, podemos usar estudante em todos os lugares
que costumava usar estudante struct.
Este tipo de def é uma estrutura anônima
e chama-aluno.
Mas se também manter o identificador de estudante
ao lado do struct palavra, como no estudante typedef struct,
podemos usar tanto o aluno e aluno struct alternadamente agora.
Eles nem mesmo têm que ter o mesmo nome.
Poderíamos escrever def estudante estrutura para Bob
e depois struct aluno e Bob
seria tipos intercambiáveis.
Independentemente do tipo de def,
precisamos do próximo identificador para a estrutura
se a definição da estrutura
é recursiva.
Por exemplo, a
def tipo struct nó
e ela será definida como um int val
e terá um ponteiro que aponta para outro nó struct.,
como na estrutura do nó * seguinte.
E então vamos chamá-lo de nós.
Essa estrutura é recursiva,
uma vez que a definição de nó struct contém dentro dele
um ponteiro para um nó de estrutura.
Observe que temos a dizer struct node * próxima
dentro da definição do nó struct,
desde a definição do tipo ainda não terminou para nos permitir simplificar este
* apenas para o próximo nó.
Você vai saber mais sobre estruturas semelhantes a este
quando se tratar de listas ligadas e árvores.
E sobre estruturas em uma função?
Isto também é perfeitamente válida.
Poderíamos ter
void func
que toma como um argumento,
estudante s
e faz algo com esse aluno.
E então nós podemos passá-lo como struct aluno assim.
Func de S1 de antes.
A estrutura comporta
exactamente como um número inteiro que quando passadas para uma função.
Func recebe uma cópia de S1
e por isso não pode modificar S1;
em vez disso, apenas a cópia do mesmo que está armazenado em S.
Se você quiser que a função de ser capaz de modificar S1,
função terá de ter um aluno * S,
e você vai ter que passar por endereço S1, assim.
Estudante * S, func & S1.
Há outra razão para passar por endereço aqui.
E se a nossa estrutura continha 100 campos?
Cada vez que passar por um estudante a func,
nosso programa precisa copiar todos os 100 campos em função do S argumento,
mesmo que ele nunca usa a vasta maioria deles.
Assim, mesmo que função não planeja modificar o aluno,
se ainda pode ser útil para passar por endereço.
Ok, o que se deseja criar um ponteiro para um struct?
Nós poderíamos fazer algo como
estudante * S
é igual malloc
tamanho do aluno.
Observe que o tamanho de ainda trabalha aqui.
Então, como vamos agora acessar o membro idade
do bloco que aponta para S?
Você pode primeiro pensar em fazer
* S.age = 4,
mas isso não funciona muito bem.
Desde que isso vai realmente ser interpretada como
* S.age entre parênteses = 4,
que não vai mesmo compilar,
desde S não é uma estrutura ou melhor, um ponteiro para uma estrutura,
e assim o ponto não vai funcionar aqui.
Nós poderíamos fazer
(* S) idade. = 4
mas os parênteses podem ficar chato e confuso.
Felizmente, temos um operador seta especial
que é algo como
S-> idade = 4.
Estas duas formas de referenciamento idade
são equivalentes
e nós realmente não precisar de o operador seta,
mas isso torna as coisas mais bonitos.
Desde que S é um apontador para um bloco de memória que contém a estrutura,
você pode pensar de S idade> como segue o ponteiro de
e agarrar o membro idade.
Então por que devemos usar sempre estruturas?
É definitivamente possível para fugir com apenas os números inteiros primitivos,
chars, apontadores e similares
que estamos acostumados;
em vez de antes de S1 e S2,
poderíamos ter tido idade1, idade2, nome1, nome2 e
todos de variáveis ​​separadas.
Isso é bom, com apenas dois alunos,
mas o que se tivéssemos 10 deles?
E se em vez de apenas dois campos,
a estrutura estudante teve 100 campos?
GPA, cursos, cor do cabelo, sexo, e assim por diante.
Em vez de apenas 10 estruturas, precisamos de mil variáveis ​​separadas.
Além disso, considere uma função
que leva esse estrutura com 100 campos com seu único argumento
e imprime todos os campos.
Se não usar uma estrutura,
cada vez que chamar essa função,
temos de passar em todas as 100 variáveis,
e se tivermos 100 variáveis ​​em uma estudante,
e 100 variáveis ​​para estudante, 2
precisamos ter certeza de que não possa passar algumas variáveis ​​de um estudante
e algumas variáveis ​​de estudante 2.
É impossível fazer esse erro com uma estrutura,
uma vez que todas as variáveis ​​são 100 contida numa única embalagem.
Apenas um par de notas finais:
Se você entendeu tudo até este ponto, ótimo.
O resto do vídeo é apenas para ser completo.
Como estruturas podem realizar qualquer tipo de ponteiro,
eles também podem conter ponteiros de função.
Se você está familiarizado com programação orientada a objetos,
isso proporciona uma maneira de usar estruturas de programa em um estilo de objeto orientado.
Mais sobre ponteiros de função em outro momento.
Também, às vezes você pode ter duas estruturas
cujas definições dependem um do outro.
Por exemplo, a
poderíamos ter struct A,
que é definido como
um apontador para um B struct,
struct B * X,
e agora podemos ter uma estrutura B
que é definido como um ponteiro
para uma estrutura A,
struct A * Y.
Mas isso não vai compilar,
desde B struct não existe no momento em que struct A está sendo compilado.
E se trocar struct struct A e B,
então nós apenas ficar com o mesmo problema;
desta vez, com struct A não existente.
Para resolver isso, podemos escrever
struct B;
antes da definição de struct A.
Isso é chamado de uma declaração para a frente.
Isso só deixa o compilador saber que
struct B é um tipo válido que será totalmente definido mais tarde ou em outro lugar.
Meu nome é Rob Bowden, e este é o CS50.
[CS50.TV]