Olá, seja bem-vindo de volta. Nesta palestra, quero falar sobre aritmética de pontos.
Agora que entendemos a relação entre matrizes e ponteiros,
esse conceito ficará mais fácil de entender.
Dizemos aritmética, mas não o fazemos - tudo
o que realmente significa é que você
pode fazer mais ou menos ou incrementar ou decrementar em um ponteiro.
Portanto, o verdadeiro poder de usar ponteiros para matrizes entra em ação quando você
deseja sequenciar os elementos de uma matriz.
Você deseja ir do primeiro elemento ao final, deseja iterar por meio deles.
Estes são os indicadores de poder reais. Como os ponteiros usam
endereços, cada elemento na matriz é apenas outro endereço.
Assim, você pode apenas fazer mais, mais nos ponteiros e ir para o próximo endereço.
Portanto, aqui o ponteiro de valores pode ser usado para acessar o primeiro
inteiro da matriz de valores.
Ele pode ser usado para acessar valores sub-0.
Portanto, se você se lembra dos valores, o ponteiro é um ponteiro que
aponta para uma matriz de inteiros.
E o atribuímos ao primeiro elemento na matriz apenas atribuindo o ponteiro ao nome da matriz.
Também poderíamos usar o endereço do operador sub-0 se quiséssemos.
Mas quando desreferenciamos o ponteiro de valores
porque ele está apontando para o primeiro elemento
na matriz, ele fornecerá o primeiro inteiro na matriz de valor sub-0.
Se você quiser referenciar o valor sub 3 por
meio da variável de ponteiro, tudo o que você precisa fazer é adicionar 3 ao ponteiro de valores
e, em seguida, aplicar o operador de indireção para desreferenciá-lo.
Então você pode simplesmente fazer algo assim. Você pode dizer o ponteiro dos valores mais 3 e
anular a referência a ele com o asterisco.
E você geralmente coloca o asterisco fora das aspas para deixar isso claro.
Mas o que isso está fazendo é dizer que o
ponteiro de valores, que é um endereço do primeiro elemento na matriz, está adicionando 3 a ele.
E então ele vai realmente adicionar para cada bytes para inteiros,
vai multiplicar os bytes pelos inteiros.
Mas isso vai essencialmente apontar para o sub
3, o quarto elemento da matriz.
Portanto, na expressão asterisco valores ponteiro mais i que pode
ser usado para acessar qualquer valor contido em uma matriz de valores.
Então, se você entender esta expressão, você pode adicionar qualquer coisa a i e
isso irá apontar para um array de elemento específico.
Portanto, se você quiser definir o valor de sub 10 a 27, tudo
o que você precisa fazer é se estiver usando um ponteiro,
digamos que o ponteiro dos valores mais 10 e, em seguida, cancele a referência e diga igual 27.
Então você vê a sintaxe diferente aqui.
Novamente, é a conveniência da notação, mas também é mais eficiente em termos do próprio programa.
Portanto, os ponteiros, por estarem tão intimamente relacionados aos arrays,
você pode acessar facilmente os elementos apenas incrementando os ponteiros
decrescentes ou adicionando ou subtraindo valores de um ponteiro.
Muito, muito útil.
Para definir o ponteiro de valores para apontar para o segundo elemento da matriz de
valores, você pode aplicar o operador de endereço ao valor sub 1 e atribuir os resultados ao ponteiro de valores.
Nós vimos isso. Esta é apenas outra maneira de fazer a mesma
coisa que mencionei antes, se quiser usar o suboperador de endereço.
Você sempre pode fazer isso se
quiser, mas é muito mais conveniente fazer aritmética de ponteiros.
Se o ponteiro de valores apontar para um valor
sub-0, você pode definir no ponto de valores de um simplesmente adicionando um
ao ponteiro de valor de valores. E é isso que realmente queremos chegar com a aritmética pontual.
Tudo que você precisa fazer é dizer que os valores apontam ou
mais é igual a um, e agora o ponteiro dos valores está apontando para o segundo elemento na
matriz ou o primeiro índice.
Notação muito, muito boa, muito fácil de fazer.
Portanto, esta é uma expressão perfeitamente válida em ce
pode ser usada para ponteiros para qualquer tipo de dados, seja um
caractere inteiro ou qualquer coisa. E você provavelmente deve estar pensando em como isso pode ser útil nos personagens.
Se você tiver um ponteiro de caractere, agora você pode acessar
cada elemento, cada caractere em uma string, apenas fazendo um sinal de mais em um ponteiro.
Os operadores de incremento e decremento mais mais e menos menos
são particularmente úteis ao lidar com esses ponteiros porque
você normalmente desejará ir de um elemento para o próximo e assim por diante.
Não é tão comum somar 22 ou menos 20 porque
geralmente você está indo em sequência.
Portanto, usar o operador de incremento em um ponteiro tem o mesmo efeito que adicionar um ao ponteiro.
Usar o operador de decremento tem o mesmo efeito que subtrair um do ponteiro.
Portanto, dizer o ponteiro dos valores mais mais
vai definir o ponteiro dos valores apontando para o próximo inteiro na matriz de valores.
Menos menos deve ser o ponteiro dos valores Vai definir
o ponteiro dos valores apontando para o inteiro anterior na matriz de valores.
Mas você deve ter cuidado ao fazer o menos
menos porque quer ter certeza de que está pelo menos na matriz e não em 0.
E o mesmo vale para mais mais.
Se você está no final do array, não quer ter erros fora dos limites.
Portanto, certifique-se de que o ponteiro de valores, se você
estiver diminuindo, não estava apontando para o início da matriz de valores inicialmente.
Outro exemplo aqui em
que vamos realmente somar todos os elementos em array,
você vê que temos uma função de soma
de array e a função recebe
um array e também um número inteiro constante como parâmetros.
Dentro da função, vamos criar um inteiro.
Vamos inicializar essa soma inteira para 0 e criar um ponteiro inteiro, um
ponteiro para do tipo int.
Também vamos criar um ponteiro que
é constante.
Isso significa que você não pode alterar o endereço dele.
Sempre será array mais n e será denominado array end.
Estamos fazendo isso porque torna nosso loop mais eficiente se configurá-lo para ir
até o final do array e apenas olhar para o ponteiro.
Portanto, o fim da matriz está apontando para o endereço do fim da matriz.
Podemos dizer array, que é o que é passado e então n é
o tamanho,
o tamanho do array.
Agora, o loop for inicializará o ponteiro da variável de controle do loop, que
é um ponteiro para o array. E tudo o que você precisa
fazer é, se quiser atribuir um ponteiro ao primeiro elemento de um array, tudo o que você precisa fazer
é dizer que o ponteiro é igual ao array.
E então nossa condição de saída do loop é se o ponteiro for menor que o final do array.
Lembre-se de que um ponteiro é um endereço e o final do array também é um endereço.
Portanto, estamos dizendo que se o endereço no ponteiro for menor que o ponteiro
n, queremos executar o corpo do loop.
O ponteiro é apenas um número inteiro, é um endereço hexadecimal.
Cada vez que incrementamos, ele vai para o próximo endereço. Temos o endereço final,
então podemos dizer vá até o final.
E então estamos incrementando o próprio ponteiro, que vai
incrementar o endereço para ir para o próximo elemento na matriz essencialmente porque
é para isso que estamos apontando.
Então temos dentro do corpo do nosso loop, dizemos soma mais ponteiro de igual.
Estamos desreferenciando o ponteiro para obter o valor
porque lembre-se de que queremos obter o valor que não queremos, o endereço do
ponteiro ou o endereço para o qual o ponteiro está apontando.
E então, no final, devolvemos a soma. Portanto, isso vai somar
todos os elementos em uma matriz.
Você notará no principal, nós também fizemos uma declaração da função lá
em oposição à parte superior do arquivo. Normalmente gosto de colocá-los no início do arquivo.
Mas, no principal, criamos uma matriz de 10 elementos, 3 7 negativos 9 e assim por diante.
Em seguida, passamos a matriz ou uma soma e
especificamos o tamanho como 10.
E o que você vai notar é que ele retorna o valor que é a soma do array.
Portanto, é muito, muito bom usar esta aritmética de ponto para iterar por meio de um array,
podemos simplesmente adicionar o
sinal de adição ao próximo endereço e também olhar para o endereço final para pular.
Isso é mais eficiente com o ponteiro olhando para o endereço final,
em oposição a um contador olhando para menos de n.
E você também notou que as criamos como constantes porque as constantes não mudam
e isso é mais eficiente com o compilador.
A matriz aqui é um ponteiro constante, o que significa que o endereço não pode ser alterado.
Você também deve ter notado neste
exemplo que para passar um array para uma função, você simplesmente especifica o nome do array.
Então sabemos como passar a função aumentar. E para produzir um ponteiro para um array,
você só precisa especificar o nome do array.
Vimos isso quando atribuímos o primeiro elemento do array a um ponteiro.
Então, o que isso implica é que a chamada para a função de
soma do array, que foi passada para a função, era na verdade um ponteiro para os valores do array.
E isso realmente quer dizer que arrays e ponteiros estão muito, muito intimamente relacionados, que um
array nada mais é do que um ponteiro.
E isso explica porque você é capaz de alterar os elementos de um array de dentro de uma função.
Porque até este ponto, quando você passa dados para uma função, esses dados não
são alterados fora dessa função, a menos que seja um ponteiro.
Porque é por isso que temos que passar o endereço para o scanf.
A única maneira de os elementos serem alterados fora de uma
função é passando ponteiros para uma função.
E como os elementos são modificados dentro dessa função, isso implica
que você está passando um ponteiro.
E isso é apenas mais uma prova
de que, quando você, os arrays e os ponteiros são muito, muito semelhantes, os arrays são, na verdade,
ponteiros usando uma sintaxe diferente.
Vamos falar sobre como podemos passar por referência ou realmente passar uma
cópia de uma referência, o que permitirá
que você altere dados em uma função fora dessa função.
Se você se lembra de um dos nossos
desafios anteriores, sempre que queríamos alterar os dados em uma função, tínhamos
que usar uma variável global.
Porque não entendíamos o conceito de
passagem por referência e não entendíamos o conceito de ponteiros.
Mas eu mencionei anteriormente também que uma das vantagens dos ponteiros é
que agora você pode alterar os dados dentro de uma função e eles serão refletidos fora dessa função.
Mas essa é outra palestra.
Mas esse conceito por si só, por causa do exemplo anterior, está demonstrando
como os arrays são essencialmente ponteiros.
Portanto, você pode se perguntar por que o parâmetro formal dentro da função não é declarado como um ponteiro.
Bem, pode ser. Poderíamos simplesmente fazer algo como isto, int array sum, int star array.
Não precisamos declarar isso como um array.
É perfeitamente válido porque arrays e ponteiros são os mesmos que podemos dizer int star array.
Mencionamos que eles estão intimamente relacionados.
Portanto, você pode declarar um tipo de array como um tipo de array de
ints dentro da função de soma do array ou pode declará-lo como um ponteiro para int.
E é por isso que você vê muitas funções que aceitam matrizes como parâmetros ou
como argumentos em que os parâmetros são, na verdade, ponteiros.
Portanto, se você for usar números de índice para fazer referência aos elementos de um array que é
passado para uma função, declare o parâmetro como um array.
Mais uma vez, a conveniência da notação, é apenas
uma forma diferente de notação, usando colchetes e subscritos ou usando um ponteiro.
O array em si é geralmente mais fácil de
ler em termos de manutenção do programa, pois reflete mais corretamente o uso do array pela função.
Mas o ponteiro é mais fácil de usar.
E se você estiver usando um argumento como um ponteiro para o array, declare que é do
tipo ponteiro no parâmetro formal.
Então aqui está um exemplo com a notação de ponteiro da função
onde o exemplo anterior estava usando uma notação de array.
Aqui, apenas dizemos int start array
e o que você notará é que a função imediatamente se
torna muito menor, porque não temos que atribuir o ponteiro ao array para o
primeiro elemento como fizemos.
O loop também se torna muito menor porque não
precisamos fazer essa atribuição na primeira instrução.
Podemos apenas dizer até que o array seja menor que o final do array
e podemos incrementar o array. Portanto, é um pouco menos
código, ainda está muito claro o que está acontecendo, se você entender arrays e ponteiros.
Estamos passando o array int star
e não precisamos mais inicializar esse array porque o estamos
passando no ponteiro, não inicializamos mais o ponteiro.
E então estamos configurando o endereço do final da matriz
para um ponteiro constante,
fim da matriz. Usamos isso para pular
para fora do loop, e apenas dizemos soma mais igual a
matriz de estrelas, usando o operador de indireção para desreferenciar a matriz novamente, retornando a soma.
E então a função principal é exatamente a mesma, exceto que a declaração agora é um ponteiro em oposição a um array.
Portanto, aqui estão 2 exemplos usando notações diferentes, mas fornecendo a mesma funcionalidade, e
é por isso que você vê muitos ponteiros como parâmetros dentro de
um parâmetro de função.
Então, para resumir, aqui estão algumas coisas que são válidas quando você usa
ponteiros e coisas que não são válidas.
Portanto, se declararmos algumas variáveis aqui, declaramos um array chamado gain e ele
continha 3 elementos e, em seguida, declaramos 2 ponteiros.
Agora, nessas dicas, podemos fazer aritmética. Podemos dizer ponteiro um mais mais.
Podemos dizer que ponto ou 2 é igual a ponto ou um mais 2.
Podemos até dizer que o ponteiro 2 é igual a ganho mais um.
É perfeitamente válido fazer isso porque você tem ponteiros e está modificando os ponteiros pelo endereço,
então você pode fazer aritmética de pontos.
Você não pode fazer aritmética de pontos em matrizes. Portanto, você não pode dizer ganhar mais mais.
Você não pode dizer o ponteiro 2 0. 2 mais 0. 1
porque esses são endereços.
E você não está realmente apontando para
nada dentro de uma matriz.
E você não pode multiplicar, ganhe pontos de tempo ou um para ganhar um ponto ou 2.
Esses são inválidos.
Portanto, preste atenção à sintaxe correta para a aritmética de ponteiros
e também entenda que a aritmética de pontos só pode ser aplicada a ponteiros,
não a matrizes.
Além disso, funções que processam matrizes usam ponteiros como argumentos.
Você pode escolher entre notação de array e notação de ponteiro para escrever
funções de processamento de array.
Portanto, se você for processar a função aleatória, é perfeitamente normal usar um ponteiro como parâmetro.
Você pode escolher qual deseja usar.
Mas usar ponteiros geralmente é menos código e mais eficiente.
Usar a notação de array torna mais óbvio que a função está trabalhando com
arrays e a notação de array tem uma aparência mais familiar para programadores que
têm algum conhecimento de programação em certas linguagens.
Portanto, se você programar antes e Fortran e Pascal e assim por diante,
você pode usar a notação de seta.
Outros programadores podem estar mais acostumados a trabalhar com ponteiros e podem achar a notação
de ponteiro mais natural, apenas faz mais sentido.
É mais próximo da linguagem de máquina usando a aritmética
de ponto e a notação de ponteiro com alguns compiladores que leva a um código mais
eficiente, outra razão para usá-lo.
Então, vamos dar uma olhada nesses exemplos dentro dos blocos
de código.
Então, aqui está nosso exemplo dos slides. Temos nossa declaração de função na linha 3.
É uma soma de matriz.
E neste exemplo, vamos usar a notação de array.
Então, vamos usar os colchetes quando usarmos índices.
E vamos chamá-lo de passagem na
matriz de valores e passagem de tamanho.
Portanto, a função de soma da matriz leva uma matriz de inteiros. Bem, a primeira coisa que você precisa
fazer é criar o ponteiro que deseja usar para aritmética de
pontos na linha 14. E então você tem que atribuir
o final da matriz à matriz de endereço mais o tamanho.
Esse é o fim do array, que agora você pode usar para sair do loop.
Mas temos que atribuir o ponteiro ao array.
Sabemos que podemos atribuir arrays a ponteiros para
apontar para o primeiro elemento usando apenas o nome do array.
Não temos que usar o endereço do operativo.
Poderíamos, se quiséssemos, poderíamos realmente fazer algo assim.
E isso também é bom.
E então nós adicionamos mais o ponteiro. Estamos incrementando o ponteiro porque tudo o
que está fazendo é incrementado para o próximo endereço. Ele está apontando para o próximo elemento na matriz.
E então, na linha 18, estamos desreferenciando o ponteiro para calcular a soma, soma igual,
soma mais o valor do ponteiro para o qual ele está apontando.
Então, se construirmos isso, teremos um aviso, que é principal e
não int, queremos mudar isso porque é bom
retornar valores de erro do principal e apenas
dizer return 0.
Você poderia retornar se houvesse um erro no
principal, você retorna um negativo. Agora que rodamos isso, você verá que ele apenas executa a soma
dos valores na matriz, que é 3 mais 7 mais 9 negativo e assim por diante, nem
mesmo tenho certeza do que é, mas parece que é 21.
Agora podemos modificar facilmente este parâmetro de array para
receber um ponteiro, apenas declarando o asterisco antes do ponteiro.
Chamamos isso da mesma maneira. Nós apenas modificamos. Não precisamos mais declarar
o ponteiro. Provavelmente queremos mudar
o nome para facilitar, mas não precisamos mais declarar este ponteiro.
Ainda queremos obter o final do array
e não precisamos mais atribuí-lo.
Podemos apenas ter uma coisa vazia lá. E pode ser mais útil ter um loop while aqui.
Mas se não tivermos nenhuma atribuição, podemos simplesmente colocar o ponto-e-vírgula lá.
E agora estamos bem. Ainda queremos retirá-lo da referência e ainda queremos devolvê-lo.
Mas se
construirmos isso, queremos ter certeza
de definir a declaração da função como um ponteiro, uma vez que a alteramos.
E pode ser qualquer nome, mas seremos consistentes.
Agora, queremos ter
certeza de que estamos usando novamente todas
as variáveis que alteramos.
Então, agora que construímos com sucesso, nós o executamos e você
vê o mesmo resultado que é 21.
Portanto, entenda essa diferença entre usar ponteiros como parâmetros formais em matrizes,
você
pode usá-los de forma intercambiável. É apenas uma notação de conveniência.
Mas normalmente você tem menos código quando usa um ponteiro.
E você pode manipulá-lo mais e fazer coisas mais poderosas, geralmente
é mais eficiente também baseado no compilador. Obrigada.