[Powered by Google Translate] [Sección 4 - máis cómodo]
[Rob Bowden - Harvard University]
[Esta é CS50. - CS50.TV]
Temos un exame mañá, se vostedes non sabían diso.
É basicamente sobre todo o que podería ter visto en clase ou debería ter visto en clase.
Isto inclúe agullas, a pesar de seren un tema moi recente.
Debe, polo menos, entender os altos niveis de los.
Calquera cousa que se foi en clase, ten que entender o quiz.
Entón se ten preguntas sobre eles, pode preguntar-lles agora.
Pero esta vai ser unha sesión moi liderado por estudantes, onde vostedes preguntas,
por iso espero que as persoas teñen preguntas.
Alguén ten dúbidas?
Si >> [Alumno] pode ir máis de punteiros de novo?
Vou pasar por riba de punteiros.
Todas as súas variables, necesariamente, vivir na memoria,
pero xeralmente non hai problema con iso e acaba de dicir x + 2 e + 3 y
eo compilador pode descubrir onde as cousas están a vivir para ti.
Unha vez que está lidando con punteiros, agora está explícitamente usando os enderezos de memoria.
Así, unha única variable só vai vivir nun único enderezo en calquera momento.
Se queremos declarar un punteiro, que é o tipo vai parecer?
>> Quero declarar un punteiro p. O que fai o tipo de aspecto?
[Estudante] int * p. Si >>. Así, int * p.
E como fago para facelo apuntar x? >> [Alumno] ampersand.
[Bowden] Entón comercial é chamado literalmente o enderezo do operador.
Polo tanto, cando digo & x está quedando o enderezo de memoria da variable x.
Entón agora eu teño o punteiro p, e en calquera lugar no meu código podo usar p *
ou eu podería usar X e vai ser exactamente a mesma cousa.
(* P). O que se está facendo? O que significa que a estrela significa?
[Estudante] significa un valor nese punto. Si >>.
Entón, se miramos para el, pode ser moi útil para aproveitar os diagramas
onde esta é unha pequena caixa de memoria para x, que pasa de ter o valor 4,
entón temos unha pequena caixa de memoria para p,
e así p apunta x, para que debuxe unha frecha de p para x.
Así, cando dicimos p * estamos dicindo ir a caixa que é p.
Star é seguir a frecha e, a continuación, facer o que quere con esta caixa aí.
Entón eu podo dicir * p = 7, e que pode para o cadro que é x e cambio que a 7.
Ou eu podería dicir int z = * p * 2; Isto é confuso porque é estrela estrela.
A estrela é unha dereferencing p, outra estrela está multiplicando por 2.
Repare que eu podería ter tan ben substituíu o p * con x.
Podes usalos da mesma forma.
E máis tarde eu podo ter punto P para unha cousa totalmente nova.
Só podo dicir p = &z;
Entón, agora p sen puntos máis longos para x, que apunta a z.
E en calquera momento que fago p * é o mesmo que facer z.
Entón o único útil sobre iso é cando comezan a entrar en funcións.
>> É unha especie de inútil para declarar un punteiro que apunta a algo
e entón está só dereferencing-lo
cando podería ter usado a variable orixinal para comezar.
Pero cando entra en funcións - entón imos dicir que temos algunha función, int foo,
que leva un punteiro e só fai * p = 6;
Como vimos antes, con intercambio, non se pode facer un intercambio de efectivo e unha función separada
por só pasando enteiros porque todo na C está sempre pasando por valor.
Mesmo cando está pasando punteiros está pasando por valor.
O que pasa é que eses valores son enderezos de memoria.
Polo tanto, cando digo foo (p), eu estou pasando o punteiro para a función foo
e, a continuación, fai foo * p = 6;
Así, dentro desa función, * p é aínda equivalente a x,
pero eu non podo usar x dentro desa función, porque non é ámbito dentro desa función.
Entón * p = 6 é a única forma que podo acceder a unha variable local doutra función.
Ou, ben, os punteiros son o único xeito que podo acceder a unha variable local doutra función.
[Alumno] Digamos que quería volver a un punteiro. Como exactamente fai iso?
[Bowden] Voltar un punteiro como algo int y = 3; retorno e y? >> [Estudante] Yeah.
[Bowden] Okay. Vostede non debe facelo. Isto é malo.
Eu creo que vin nestes diapositivas das clases que comezaron a ver neste diagrama toda a memoria
onde ata aquí ten o enderezo de memoria 0
e aquí ten de enderezo de memoria 4 GB ou 2 elevado á 32.
Entón tes algunhas cousas e algunhas cousas e entón ten a súa pila
e ten a súa pila, que só comezou a aprender sobre, crecendo.
[Alumno] non é a pila enriba da pila?
>> Si A pila é por riba, non é? >> [Alumno] Ben, el puxo 0 encima.
[Estudante] Oh, el puxo 0 encima. >> [Alumno] Ah, ok.
Disclaimer: Calquera lugar con CS50 vai velo deste xeito. >> [Alumno] Okay.
É que cando está a ver primeiro pilas,
como cando pensar en unha pila pensas de apilar as cousas enriba da outra.
Entón, temos a tendencia de virar esta en torno de xeito conxunto está crecendo como unha pila normalmente
en vez da pila colgada abaixo. >> [Alumno] non montes tecnicamente crecer moito, aínda que?
Depende do que entende por crecer.
A pila e heap crecer sempre en direccións opostas.
Unha pila é sempre crecendo no sentido de que está crecendo
para enderezos de memoria máis altas, ea pila está crecendo para abaixo
en que é crecente para enderezos menores de memoria.
Así, o cumio é 0 e no fondo e enderezos de memoria de alta.
Ambos están crecendo, só en direccións opostas.
[Estudante] Eu só quería dicir que porque dixo que poñer pila na parte inferior
porque parece máis intuitivo porque, para a pila para comezar na parte superior de unha pila,
pila é por riba de ti tamén, entón iso é - >> Yeah.
Tamén pensa da pila como o crecemento e maior, pero a pila máis.
Así, a pila é o que nós medio que queremos mostrar crecendo.
Pero en todo lugar que mira de outra forma vai amosar o enderezo 0 arriba
eo enderezo de memoria máis alto na parte inferior, por iso esta é a súa visión usual de memoria.
>> Ten unha pregunta?
[Alumno] Pode dicir máis sobre o monte?
Si Eu vou chegar a iso nun segundo.
En primeiro lugar, por que volver para devolver & y é unha cousa ruín,
na pila ten unha morea de cadros de pila que representan todas as funcións
que foron chamados.
Entón, ignorando as cousas anteriores, o principio da súa pila é sempre vai ser a función principal
xa que é a primeira función que está a ser chamado.
E entón cando chamar outra función, a pila vai medrar para abaixo.
Entón, se eu chamar algunha función, foo, e fai a súa estrutura propia pila,
pode chamar dalgunha función bar, que recibe o seu cadro de pila propia.
E bar pode ser recursiva e que podería chamarse,
e para que segunda chamada para a barra vai estar a súa estrutura propia pila.
E así o que pasa nestes cadros de pila son as variables locais
e todos os argumentos da función que -
Todas as cousas que están no lugar delimitado para esta función vai neses cadros de pila.
Entón isto significa que cando dixo algo así como bar é unha función,
Eu só vou declarar un enteiro e, a continuación, voltar un punteiro para este enteiro.
Entón onde é que y vivir?
[Estudante] y vive no bar. >> [Bowden] Yeah.
En algún lugar neste pequeno cadrado de memoria é unha praza que ten littler y nel.
Cando volten & y, estou volvendo un punteiro para este pequeno bloque de memoria.
Pero entón, cando a función devolve o seu cadro de pila é pego na pila.
E é por iso que se chama de pila.
É como a estrutura de datos de pila, se sabe o que é.
Ou incluso como unha pila de bandexas é sempre o exemplo
principal a ir na parte inferior, a continuación, a función de primeiro ligar está a ir enriba do que,
e non pode volver ao inicio ata voltar todas as funcións que foron chamados
que foron colocados na parte superior do mesmo.
>> [Alumno] Entón, se realmente fixo retornar a Y &, ese valor está suxeito a modificación sen previo aviso.
Si, é - >> [alumno] Podería ser substituído. Si >>.
É completamente - Se tentar -
Esta sería tamén unha barra * int porque está retornando un punteiro,
así, o seu tipo de retorno é int *.
Se tentar usar o valor de retorno desa función, é un comportamento indefinido
porque ese punteiro apunta a memoria malo. >> [Alumno] Okay.
Entón, o que, por exemplo, declarou int * y = malloc (sizeof (int))?
Así é mellor. Si
[Alumno] Nós conversas sobre como cando arrastrar as cousas para a nosa lixo
eles non están realmente borrado, só perden os seus punteiros.
Polo tanto, neste caso realmente borrar o valor ou é aínda existe na memoria?
Para a maior parte, vai estar alí.
Pero imos dicir que ocorrer para chamar algunha outra función, Baz.
Baz vai estar a súa estrutura propia pila aquí.
Vai ser a substitución de todas estas cousas,
e entón se tentar máis tarde e usar o punteiro que ten antes,
non vai ser o mesmo valor.
Vai cambiar só porque chamou o Baz función.
[Alumno] Pero se non tivésemos, estariamos aínda obter 3?
[Bowden] En toda probabilidade, que o faría.
Pero non pode contar con iso. C só di comportamento indefinido.
>> [Estudante] Oh, é verdade. Okay.
Entón, cando quere voltar un punteiro, que é o lugar onde malloc vén en uso.
Eu estou escribindo en realidade, só devolver malloc (3 * sizeof (int)).
Nós falaremos sobre malloc máis nun segundo, pero a idea de malloc é todo das súas variables locais
sempre van para a pila.
Calquera cousa que é malloced vai na pila, e será para sempre e sempre na pila
ata que explicitamente libertá-lo.
Entón isto significa que cando malloc algo, que vai sobrevivir tras o retorno da función.
[Alumno] Será que vai sobrevivir despois de que o programa deixa de funcionar? Non >>
Ok, entón vai estar alí ata que o programa é todo o camiño feito en execución. Si >>.
Podemos ir máis detalles do que acontece cando o programa deixa de funcionar.
Podes ter para me lembrar, pero que é unha cousa separada enteiramente.
[Estudante] Entón malloc crea un punteiro? Si >>.
Malloc - >> [estudante] Coido que malloc designa un bloque de memoria que un punteiro pode usar.
[Bowden] Eu quero que diagrama novo. >> [Alumno] Entón, esa función funciona, aínda que?
[Alumno] Si, malloc designa un bloque de memoria que pode usar,
e, a continuación, retorna o enderezo do primeiro bloque de memoria que.
>> [Bowden] Yeah. Entón, cando malloc vostede, está pegando un bloque de memoria
que está actualmente no heap.
Se a pila é moi pequeno, entón a pila só vai medrar, e crece nesa dirección.
Entón, digamos que a pila é moi pequeno.
Entón, está a piques de crecer un pouco e voltar un punteiro para este bloque que só creceu.
Cando o material libre, está facendo máis espazo no heap,
Entón unha chamada posterior para malloc pode reutilizar que a memoria que xa liberado.
A cousa importante sobre malloc e free é que lle dá o control completo
sobre a vida destes bloques de memoria.
As variables globais son sempre vivo.
As variables locais están vivos dentro do seu alcance.
Así que pasar unha chaveta, as variables locais están mortos.
Memoria Malloced está vivo cando quere estar vivo
e despois é liberado cando diga a el para ser lanzado.
Estes son realmente os únicos tres tipos de memoria, realmente.
Hai xestión automática de memoria, que é a pila.
As cousas acontecen automaticamente para ti.
Cando di int x, memoria é alocada para int x.
Cando x sae do ámbito, a memoria é recuperado para x.
Despois, hai a xestión de memoria dinámica, que é o que malloc é,
que é cando ten control.
Decide dinámicamente cando a memoria debe e non debe ser alocado.
E despois hai o estático, que só significa que vive para sempre,
que é o que as variables globais son.
Son só sempre na memoria.
>> Preguntas?
[Estudante] Pode definir un bloque de só usando claves
pero non ter que ter un? se declaración ou declaración de tempo ou algo así
Podes establecer un bloque como unha función, pero que ten chaves tamén.
[Alumno] Entón, non pode só ter como un par chou de claves no seu código
que teñen variables locais? >> Si, pode.
Dentro do bar int poderiamos ter {int y = 3;}.
Isto debería estar aquí.
Pero que define completamente o ámbito de int y.
Despois de que chaveta segundo, y non pode ser máis usado.
Vostede case nunca o fan, con todo.
Volvendo ao que acontece cando un programa remata,
hai unha especie de mentira equívoco / media que damos a fin de só facer as cousas máis fáciles.
Nós dicimos a vostedes que cando reservar memoria
está alocando algún anaco de memoria RAM para esta variable.
Pero non está realmente tocar directamente RAM sempre nos seus programas.
Se pensar sobre iso, como eu deseño -
E, de feito, se pasar o GDB vai ver a mesma cousa.
Independentemente do número de veces que executar o programa ou o programa que está en execución,
a pila sempre vai comezar -
sempre vai ver variables en torno a algo oxbffff enderezo.
É xeralmente en algún lugar na rexión.
Pero como pode, eventualmente, ter dous programas de punteiros para a memoria mesmo?
[Alumno] Hai algunha designación arbitraria de onde oxbfff se quere que sexa na memoria RAM
que realmente pode estar en diferentes lugares, dependendo de cando a función foi chamada.
Si O termo é a memoria virtual.
A idea é que cada proceso único, cada programa que está en execución no ordenador
ten o seu propio - imos supor que 32 bits - espazo de enderezo completamente independente.
Este é o espazo de enderezo.
El ten as súas propias completamente independentes 4 gigabytes de usar.
>> Entón, se executar dous programas ó mesmo tempo, este programa vese catro gigabytes para si,
este programa vese catro gigabytes para si,
e é imposible para este programa dereference un punteiro
e acabar coa memoria a partir deste programa.
E o que a memoria virtual é un mapeamento dun espazo de enderezo de procesos
a cousas reais na RAM.
Polo tanto, cabe ao seu sistema operativo para saber que,
hey, cando este cara oxbfff punteiro dereferences, que realmente significa
que quere RAM byte 1000,
mentres que se este programa oxbfff dereferences, realmente quere RAM byte 10000.
Eles poden ser arbitrariamente afastadas.
Isto é aínda certo das cousas dentro dun espazo único de procesos de enderezo.
Entón, como se ve todos os 4 gigabytes para si mesmo, pero imos dicir -
[Alumno] Será que cada proceso -
Imos dicir que ten un ordenador con só 4 gigabytes de memoria RAM.
Cada proceso ver a 4 gigabytes? Si >>.
Pero os 4 gigabytes que ve é unha mentira.
É só el cre que ten toda a memoria que xa non coñece ningún outro proceso existe.
É só usar a memoria, tanto como realmente precisa.
O sistema operativo non vai dar RAM para este proceso
se non é utilizar calquera memoria en toda esta rexión.
Non vai dar-lle a memoria para esa rexión.
Pero a idea é que - eu estou tentando pensar - Eu non podo pensar nunha analoxía.
Analoxías son difíciles.
Unha das cuestións de memoria virtual ou unha das cousas que está resolvendo
é a de que os procesos deben ser completamente alleos un ao outro.
E así pode escribir calquera programa que só dereferences calquera punteiro,
como só escribir un programa que se * (ox1234),
e iso é o enderezo de memoria dereferencing 1234.
>> Pero cabe ao sistema operativo para despois traducir o que significa 1234.
Así, 1234 pasa de ser un enderezo de memoria válido para este proceso,
como é na pila ou algo así, entón iso vai devolver o valor do enderezo de memoria
na medida en que o proceso sabe.
Pero se 1234 non é un enderezo válido, como acontece á terra
nalgún pedazo de memoria aquí que está alén da pila e ademais da pila
e realmente non teño usado que, a continuación, que é cando facer as cousas como segfaults
porque está tocando memoria que non debe tocar.
Isto tamén é certo -
Un sistema de 32 bits, 32 bits significa que ten 32 bits para definir un enderezo de memoria.
É por iso que os punteiros son 8 bytes, porque 32 bits son 8 bytes - ou 4 bytes.
Os punteiros son 4 bytes.
Entón, cando ve un punteiro como oxbfffff, que é -
Dentro dun determinado programa pode só construír calquera punteiro arbitraria,
en calquera lugar de ox0 para boi 8 f 's - ffffffff.
[Alumno] Non dixen que son 4 bytes? Si >>.
[Alumno] A continuación, cada byte terá - >> [Bowden] hexadecimal.
Hexadecimal - 5, 6, 7, 8. Entón punteiros vai sempre ver en hexadecimal.
É exactamente como nós clasificamos punteiros.
Cada 2 díxitos do hexadecimal é un byte.
Entón alí vai ser de 8 díxitos hexadecimais de 4 bytes.
Así, cada punteiro único nun sistema de 32 bits vai ser 4 bytes,
o que significa que, no seu proceso, pode construír calquera arbitrarias 4 bytes
e facer un punteiro de fóra,
o que significa que, na medida é consciente, pode dirixir un enteiro 2 para os 32 bytes de memoria.
Aínda que realmente non ten acceso a iso,
mesmo se o seu ordenador ten só 512 megabytes, el pensa que ten esa cantidade de memoria.
E o sistema operativo é intelixente o suficiente para que el só pode reservar o que realmente precisa.
Non só tes que ir, oh, un novo proceso: catro concertos.
>> Si >> [Alumno] O que é que o boi significa? Por que escribe?
É só o símbolo para hexadecimal.
Cando ve un número con inicio boi, as cousas son sucesivas hexadecimal.
[Alumno] Vostede estaba explicando o que pasa cando un programa remata. Si >>.
O que acontece cando un programa remata é o sistema operativo
só elimina os mapeamento que para estes enderezos, e é iso.
O sistema operativo pode agora dar só que a memoria a outro programa para usar.
[Alumno] Okay.
Entón, cando aloca algo na pila ou as variables de pila ou global ou calquera cousa,
todos eles simplemente desaparecer así que o programa remata
porque o sistema operativo é agora a liberdade de dar esa memoria para calquera outro proceso.
[Alumno] Aínda que probablemente hai aínda valores escritos en? Si >>.
Os valores son probablemente aínda está alí.
É só iso que vai ser difícil chegar a eles.
É moito máis difícil para chegar a eles que é para chegar a un ficheiro eliminado
porque o tipo de ficheiro que foi eliminado está alí por un longo tempo e disco duro é moito maior.
Por iso, vai a substituír partes diferentes de memoria
antes de que aconteza para substituír o anaco de memoria que o ficheiro utilizado para estar.
Pero a memoria principal, memoria RAM, percorrer moito máis rápido,
por iso vai moi rapidamente ser substituído.
Dúbidas sobre esta ou calquera outra cousa?
[Alumno] Teño dúbidas sobre un tema diferente. Ok >>.
Alguén ten dúbidas sobre iso?
>> Okay. Tema diferente. >> [Alumno] Okay.
Eu estaba pasando por algúns dos tests prácticos,
e nunha delas estaba falando sobre o sizeof
eo valor que retorna ou distintos tipos de variables. Si >>.
E dixo que tanto int e longo retorno tanto 4, entón ambos son 4 bytes.
¿Hai algunha diferencia entre un int e un longo, ou é a mesma cousa?
Si, hai unha diferenza.
O patrón C -
Probablemente, vou romper.
O patrón C é como o que é C, a documentación oficial do C.
Isto é o que di.
Así, o estándar C só di que un char para sempre e sempre un byte.
Todo o que despois - un curto é sempre só definida como maior que ou igual a un char.
Isto pode ser estrictamente maior que, pero non positiva.
Un int é só definida como maior que ou igual a unha curta distancia.
E unha lonxitude é só definida como maior que ou igual a un enteiro.
E un longo tempo é maior que ou igual a lonxitude.
Entón, a única cousa que o estándar C define é a ordenación relativa de todo.
A cantidade real de memoria que as cousas levan xeralmente ata a súa implementación,
Pero é moi ben definida neste momento. >> [Alumno] Okay.
Entón shorts son case sempre vai ser de 2 bytes.
Ints son case sempre vai ser de 4 bytes.
Longs longos son case sempre vai ser de 8 bytes.
E quere, iso depende se está a usar un de 32 bits ou un sistema de 64 bits.
Así, un tempo que vai corresponder ao tipo de sistema.
Se está usando un sistema de 32 bits, como o aparello, que vai ser de 4 bytes.
Se está usando unha de 64 bits como unha morea de computadores máis recentes, que vai ser de 8 bytes.
>> Ints son case sempre 4 bytes neste momento.
Longs longos son case sempre de 8 bytes.
No pasado, o ints usado para ser só 2 bytes.
Pero teña en conta que este cumpre completamente todas esas relacións de maior e igual a.
Sempre é perfectamente permitido ter o mesmo tamaño como un enteiro,
e está tamén autorizado a ser do mesmo tamaño que unha lonxitude longo.
E iso só pasa de ser que 99,999% dos sistemas, que vai ser igual a
ou int ou un longo tempo. Depende só de 32-bit ou 64 bits. >> [Alumno] Okay.
En coches alegóricos, como é o punto decimal designada en termos de bits?
Como como binario? Si >>.
Non é preciso saber que a CS50.
Non é preciso nin saber que en 61.
Vostede non aprende que realmente en calquera curso.
É só unha representación.
Eu esquezo os loteamentos bit exactas.
A idea de punto flotante é que asignar un número específico de bits para representar -
Basicamente, todo está en notación científica.
Entón asignar un número específico de bits para representar o número en si, como 1,2345.
Eu nunca pode representar un número con máis díxitos que 5.
Entón tamén asignar un número específico de bits para que tende a ser semellante
só pode ir ata un certo número, que ese é o maior expoñente quizais,
e só pode ir ata un certo expoñente,
así é menor expoñente pode ter.
>> Eu non me lembro os bits xeito exacta son asignados a todos estes valores,
pero un certo número de bits son dedicados a 1,2345,
outro determinado número de bits son dedicados a expoñente,
e só é posible para representar un expoñente dun determinado tamaño.
[Estudante] e un dobre? É que, como un flotador extra longa? Si >>.
É a mesma cousa que un coche alegórico só que agora está a usar 8 bytes no canto de 4 bytes.
Agora vai ser capaz de utilizar 9 díxitos ou 10 díxitos,
e iso vai ser capaz de ir ata 300 en vez de 100. >> [Alumno] Okay.
E flota tamén son 4 bytes. Si >>.
Ben, unha vez máis, probablemente depende global sobre a aplicación xeral,
pero flotadores son 4 bytes, dobres son 8.
Dobres son chamados de parella, porque son o dobre do tamaño dos coches alegóricos.
[Alumno] Okay. E hai dobre dobra? >> Non hai.
Eu creo - >> [estudante] Como longs longas? Si >>. Penso que non. Si
[Estudante] En proba o ano pasado, houbo unha pregunta sobre a principal función
ter que facer parte do seu programa.
A resposta foi que non ten que ser parte do seu programa.
En que situación? Isto é o que eu vin.
[Bowden] Parece - >> [alumno] Que situación?
Ten o problema? >> [Alumno] Si, eu sempre podo puxa-lo cara arriba.
Non ten que ser, tecnicamente, pero basicamente vai ser.
[Estudante] Eu vin un en un ano diferente.
Era como verdadeiro ou falso: Un válido - >> Ah, un arquivo c.?
. [Alumno] Calquera ficheiro debe C - [ambos falando dunha vez - inintelixible]
Okay. Entón, iso é separado.
>> Unha. Arquivo c só precisa ter funcións.
Pode compilar un arquivo en código de máquina, binario, calquera que sexa,
sen que sexa executábel aínda.
Un executable válido debe ter unha función principal.
Podes escribir 100 funcións nun arquivo, pero non principais
e despois compilar que ata binario,
entón escribir outro arquivo que ten só principal, pero chama moito desas funcións
neste ficheiro binario por aquí.
E así, cando está facendo o executábel, que é o que fai o linker
é el combina estes dous arquivos binarios nun arquivo executable.
Así, un. Arquivo c non precisa ter unha función principal de todo.
E en grandes bases de código verás miles de arquivos. C e 1 ficheiro principal.
Máis preguntas?
[Alumno] Había outra cuestión.
El dixo que facer é un compilador. Verdadeiro ou falso?
E a resposta era falsa, e eu entendín por que non é como Clang.
Pero o que chamamos de facer, se non é?
Facer é, basicamente, só - Eu podo ver exactamente o que el chama.
Pero iso só fai comandos.
Facer.
Podo tirar isto. Si
Ah, si. Fai tamén o fai.
Este di que o propósito do utilidade make é determinar automaticamente
que partes dun gran programa deben ser recompilados
e emitir os comandos para recopila-los.
Podes facer facer arquivos que son absolutamente enorme.
Fai mira as marcas de tempo de arquivos e, como dixemos antes,
pode compilar arquivos individuais para abaixo, e non é ata chegar ao linker
que están xuntos nun executable.
Entón, se ten 10 arquivos diferentes e fai unha modificación nun deles,
entón o que fai vai facer é só recompilar dun ficheiro
e, despois, religar todo xuntos.
Pero é moito máis burro do que iso.
É ata a definir completamente que iso é o que debería estar facendo.
É por defecto ten a capacidade de recoñecer estas cousas selo de tempo,
pero pode escribir un ficheiro de make para facer calquera cousa.
Podes escribir un ficheiro para facer que cando escribe facelo só cd para outro directorio.
Eu estaba quedando errado porque eu todo rumbo dentro da miña Appliance
e despois eu ver o PDF do Mac
>> Entón eu vou para Finder e que eu poida facer Vai, conectar co servidor,
eo servidor de eu conectar o meu dispositivo e, a continuación, abrir o PDF
que está feita polo LaTeX.
Pero eu estaba quedando errado porque cada vez que eu precisaba actualizar o PDF,
Eu tiña que copia-lo para un directorio específico que podería acceder
e foi quedando aburrido.
Entón, en vez escribín un ficheiro make, que ten que definir a forma como fai as cousas.
Como fai iso é en PDF LaTeX.
Así como calquera outro arquivo de outra marca - ou eu creo que aínda non viu os ficheiros de facer,
pero temos no aparello un arquivo de marca global que só di:
se está compilando un ficheiro C, use Clang.
E aquí no meu arquivo make que fago eu digo,
este ficheiro que vai querer compilar con LaTeX PDF.
E por iso é LaTeX PDF que está facendo a compilación.
Facer non é compilar. É só executar estes comandos na secuencia eu especifiquei.
Por iso, corre LaTeX PDF, el copia ao directorio que quero que sexa copiado para,
que cd para o directorio e fai outras cousas,
pero todo o que fai é recoñecer cando un arquivo é modificado,
e se cambia, entón el vai executar os comandos que se quere para realizar
cando os cambios do ficheiro. >> [Alumno] Okay.
Eu non sei de onde os ficheiros fanse globais son para eu dar un ollo.
Outras preguntas? Calquera cousa do pasado quizzes? Calquera cousas punteiro?
Hai cousas sutís con punteiros como -
Eu non vou ser capaz de atopar a unha pregunta sobre el -
pero como este tipo de cousas.
Asegúrese de entender que cando eu digo int * x * y -
Este non é exactamente nada aquí, eu creo.
Pero, como * x * y, aqueles son 2 variables que están na pila.
Cando digo que x = malloc (sizeof (int)), x aínda é unha variable na pila,
malloc é unha pista no heap, e nós estamos tendo punto x no heap.
>> Entón, algo sobre os puntos de pila para o heap.
Sempre que malloc nada, está inevitablemente almacena-lo dentro dun punteiro.
Así que o punteiro estea na pila, o bloque é malloced na pila.
Moitas persoas se confunden e din int * x = malloc; x na pila.
Non ¿Que é x apunta para a pila.
x si é na pila, a non ser que, por calquera razón, x ser unha variable global,
caso en que pasa a ser noutra rexión de memoria.
Entón, manter o control, estes diagramas de caixa e frecha son bastante comúns para o quiz.
Ou se non está no exame 0, estará no cuestionario 1.
Debes saber todo iso, os pasos en compilación
sempre que tivo que responder a preguntas sobre aqueles. Si
[Alumno] Podemos ir máis desas etapas - >> Por suposto.
Antes de pasos e compilación temos o pre-procesamento,
compilación, montaxe e conexión.
Pre-procesamento. O que iso fai?
É o paso máis fácil - ben, non como -
iso non significa que debería ser obvio, pero é o paso máis doado.
Vostedes poderían implementar lo vós mesmos. Si
[Alumno] Colla o que ten no seu inclúe como este e copia e despois tamén define.
El procura por cousas como # include e # define,
e só copiar e cola que aqueles realmente significan.
Entón, cando di # include cs50.h, o pre-procesador está copiando e colando cs50.h
en que a liña.
Cando di # define x para 4, o pre-procesador pasa por todo o programa
e substitúe todas as ocorrencias de x por 4.
Así, o pre-procesador ten un arquivo C válido e xera un ficheiro válido C
onde as cousas teñen copiado e pegado.
Entón agora compilar. O que iso fai?
[Alumno] El vai de C para binario.
>> [Bowden] Non percorrer todo o camiño para binario.
[Estudante] para código de máquina, entón? >> Non é un código de máquina.
[Alumno] Asemblea? >> Asemblea.
El vai para a Asemblea antes de que vaia todo o camiño para o código C,
ea maioría das linguas facer algo así.
Escolla calquera linguaxe de alto nivel, e se está indo para recompila-lo,
é probable que compilar en etapas.
Primeiro vai compilar o Python para C, entón vai para compilar C a Asemblea,
e Asemblea vai estar traducido para binario.
Entón compilación vai trae-lo de C para Assembly.
A palabra compilando normalmente significa trae-lo a partir dun nivel máis elevado
a un menor nivel de linguaxe de programación.
Polo tanto, esta é a única etapa na compilación onde comeza cunha linguaxe de alto nivel
e acaban nunha linguaxe de baixo nivel, e é por iso que a etapa chámase compilación.
[Alumno] Durante a compilación, imos dicir que fixo # include cs50.h.
Será que o compilador recompilar o cs50.h, como as funcións que están aí,
e traducir iso en código Asemblea, así como,
ou vai copiar e pegar algo que foi pre-montaxe?
cs50.h vai practicamente nunca acabar na Asemblea.
Cousas como prototipos de función e as cousas son só para ti ter coidado.
El asegura que o compilador pode comprobar as cousas que está chamando funcións
cos tipos de retorno de dereita e os argumentos correctos e outras cousas.
>> Entón cs50.h serán pre-procesados ​​no arquivo, e entón cando está compilando
é basicamente xogado fóra despois que garante que todo está chamado correctamente.
Pero as funcións definidas na biblioteca CS50, que son separados cs50.h,
aqueles que non será compilado por separado.
Que realmente vai vir abaixo na etapa de conexión, así que nós imos chegar a iso nun segundo.
Pero, primeiro, o que é montaxe?
[Estudante] Asemblea para binario? Si >>.
Montaxe.
Non chamalo de compilación porque Asemblea é practicamente unha tradución pura de binario.
Hai unha lóxica moi pouco en ir Asemblea para binario.
É como mirar para arriba na táboa, oh, temos esa instrución;
que corresponde ao binario 01110.
E así os arquivos que a montaxe xeralmente saídas son. Arquivos o.
E arquivos. O son que estabamos dicindo antes,
como un arquivo non é preciso ter unha función principal.
Calquera ficheiro pode ser compilado para abaixo para un ficheiro a. Mentres el é un arquivo C válido.
Pode ser feita a abaixo. O.
Agora, ligando é o que realmente trae unha chea de. O ficheiros e os leva para un executable.
E entón o que fai é que liga pode pensar a biblioteca como un arquivo CS50 o ..
É un arquivo binario xa compilado.
E así, cando compilar o seu arquivo, o seu hello.c, que chama GetString,
hello.c está feita ata hello.o,
hello.o está agora en binario.
El usa GetString, polo que cómpre ir cs50.o,
eo vinculador smooshes-los xuntos e copiar GetString para este ficheiro
e sae cun executable que ten todas as funcións que precisa.
Entón cs50.o non é realmente un ficheiro do, pero está preto o suficiente para que non hai diferenza fundamental.
Entón, conectando só trae unha morea de arquivos xuntos
que por separado conter todas as funcións que teño uso
e crea o executable que vai realmente funcionar.
>> E por iso é tamén o que diciamos antes
onde pode ter 1000. arquivos C, recompila-los todos. arquivos o,
que probablemente vai levar un pouco, entón cambiar unha. arquivo c.
Só ten recompilar que 1. Arquivo C e despois conectar de novo todo o máis,
vincular todo de volta xuntos.
[Alumno] Cando estamos ligando escribimos lcs50?
Si, así lcs50. Que os signos de bandeira para o vinculador que debe estar ligando nesta biblioteca.
Preguntas?
Temos ido máis binario distinto que 5 segundos en primeira charla?
Penso que non.
Debe saber todo o SO grande que xa sabemos,
e ten que ser capaz de se lle deu unha función,
ten que ser capaz de dicir que é grande, aproximadamente. Ou ben grande, o é áspera.
Entón, se ves aniñados loops looping sobre o mesmo número de cousas,
como int i, i <n; int j, j > [alumno] n ao cadrado. >> Tende a ser n ao cadrado.
Se triplo aniñados, el tende a ser n cubos.
Entón, que tipo de cousas ten que ser capaz de apuntar inmediatamente.
Debe saber o tipo de inserción e bubble sort e merge sort e de todos aqueles.
É máis fácil entender por que eles son os n ao cadrado e n log n e todo iso
porque eu creo que houbo un quiz un ano no que, basicamente, deulle
unha implementación do bubble sort, e dixo: "O que é o tempo de execución desta función?"
Entón, se recoñecelo como unha especie de burbulla, entón podes dicir inmediatamente n ao cadrado.
Pero se ollar para el, non precisa aínda de entender que é unha especie de burbulla;
pode só dicir que este está facendo isto e isto. Este é n ao cadrado.
[Alumno] Hai exemplos difíciles que pode vir enriba con,
como unha idea semellante de descubrir?
>> Eu non creo que vai dar-lle algúns exemplos difíciles.
O bubble sort é tan resistente como iamos nós,
e aínda que, sempre que entenda que está interactuando sobre a matriz
para cada elemento da matriz, o que vai ser algo que n ao cadrado.
Hai cuestións xerais, como aquí temos - Ah.
Aínda o outro día, Doug afirmou: "Eu inventei un algoritmo que pode clasificar un array
"De n números en O (log n) o tempo!"
Así como sabemos que iso é imposible?
[Resposta do alumno inaudível] >> Yeah.
Como mínimo, ten que tocar cada elemento na matriz,
por iso é imposible de clasificar unha matriz de -
Se todo está en orde non separado, entón vai estar tocando todo na matriz,
por iso é imposible facelo en menos de O de n.
[Alumno] nos mostrou que o exemplo de ser capaz de facelo en O de n
se usa unha morea de memoria. Si >>.
E iso é - eu esquezo o que é - e contando tipo?
Hmm Que é un algoritmo de ordenación enteiro.
Eu estaba mirando para o nome especial para iso que eu non podía me lembrar a semana pasada.
Si Estes son os tipos de tipos que poden realizar as cousas en grande de n.
Pero hai limitacións, como só se pode usar números enteiros ata un determinado número.
Ademais, se está tentando clasificar Si Aí algo -
Se a súa matriz é 012, -12, 151, 4 millóns,
a continuación, o elemento único vai arruinar completamente a selección enteiro.
>> Preguntas?
[Alumno] Se vostede ten unha función recursiva, e iso só fai as chamadas recursivas
dentro dunha instrución de retorno, que é rabo recursiva,
e así que non vai utilizar máis memoria durante o tempo de execución
ou sería, polo menos, utilizar a memoria comparable como solución iterativa?
[Bowden] Si
Probablemente sería un pouco máis lento, pero non realmente.
Cola recursiva é moi bo.
Mirando de novo para cadros de pila, imos dicir que temos principal
e temos barra int (int x) ou algo así.
Esta non é unha función recursiva perfecto, pero barra de retorno (x - 1).
Entón, obviamente, que é fallo. Debe casos base e outras cousas.
Pero a idea aquí é que esta é a cola recursiva,
o que significa que cando a barra de chamadas principal que vai ter o seu cadro de pila.
Neste cadro de pila alí vai ser un pequeno bloque de memoria
que corresponde ao seu argumento x.
E así imos dicir principal pasa a chamarse bar (100);
Entón x vai comezar como 100.
O compilador recoñece que esta é unha función recursiva cola,
a continuación, cando a barra fai a súa chamada recursiva para untar,
en vez de facer un novo cadro de pila, que é onde a pila comeza a crecer en gran parte,
finalmente, el será executado na pila e entón comeza segfaults
porque a memoria comeza a chocar.
>> Entón, en vez de facer o seu propio cadro de pila, pode realizar,
Ola, eu nunca realmente precisa para volver a este cadro de pila,
Así, en vez vou substituír ese argumento con 99 e, a continuación, comezar a barra de todo.
E entón el vai facer iso de novo e vai chegar barra de retorno (x - 1),
e en vez de facer un novo cadro de pila, que vai só substituír o seu argumento actual con 98
e despois ir de volta para o inicio do bar.
Estas operacións, substituíndo este valor 1 na pila e ir de volta para o inicio,
son bastante eficaces.
Polo tanto, non é só o uso de memoria aínda que unha función propia, que é iterativo
porque está usando só un cadro de pila, pero non está sufrindo os inconvenientes
de ter que chamar funcións.
Funcións de chamada pode ser un pouco caro, porque ten que facer toda esa configuración
e desmontaxe e todas esas cousas.
Polo tanto, este recursão de cola é bo.
[Alumno] Por que non crear novos pasos?
Porque entende que non precisa.
A chamada á barra está só retornando a chamada recursiva.
Por iso, non precisa de facer calquera cousa co valor de retorno.
El só vai inmediatamente devolve-lo.
Por iso, só vai substituír o seu propio argumento e comezar de novo.
E tamén, se non ten a versión cola recursiva,
entón obter todos estes bares onde, cando esta barra retorna
ten que voltar ao seu valor para este, a continuación, que a barra retorna inmediatamente
e retorna o seu valor para este, a continuación, é só ir para voltar inmediatamente
e voltar o seu valor a este.
Entón está salvando esta aparecendo todas estas cousas fóra da pila
unha vez que o valor de retorno é só vai ser pasado por todo o camiño de volta de calquera maneira.
Entón por que non substituír o noso argumento co argumento actualizado e comezar de novo?
Se a función non é recursiva cola, se fai algo así como -
[Alumno] se bar (x + 1). Si >>.
>> Entón, se poñelas en condicións, entón está facendo algo co valor de retorno.
Ou mesmo se acaba de facer return 2 * bar (x - 1).
Entón bar agora (x - 1) precisa volver para que para calcular 2 veces ese valor,
entón agora é necesario o seu cadro de pila separada,
e agora, non importa o quão duro vostede probe, vai ter -
Esta non é a cola recursiva.
[Alumno] Será que eu intento traer unha recursão a apuntar para unha recursão de cola -
[Bowden] Nun mundo ideal, pero na CS50 non precisa facer iso.
A fin de obter recursão de cola, xeralmente, ten establece un argumento adicional
onde bar terá int x en y
e y corresponde á última cousa que quere volver.
Entón esta vai estar retornando bar (x - 1), 2 * y.
Entón, iso é só un alto nivel como transformar as cousas para ser cola recursiva.
Pero o argumento extra -
E entón, ao final, cando chegar ao seu caso base, acaba de volver y
porque foi acumulando o tempo o valor de retorno que quere.
Vostede medio que ten feito de forma iterativa, mais a través de chamadas recursivas.
Preguntas?
[Estudante] Quizais sobre a aritmética de punteiro, coma cando se usa cordas. >> Suposto.
Aritmética de punteiro.
Ao usar cordas é fácil porque as cordas son estrelas char,
chars son para sempre e sempre un único byte,
e así a aritmética de punteiro é equivalente a aritmética regular, cando está lidando con cordas.
Nós só dicir que char * s = "Ola".
Polo tanto, temos un bloque na memoria.
Precisa de 6 bytes, porque sempre precisa do terminador nulo.
E char * s vai apuntar para o inicio desta matriz.
Así s apunte alí.
Agora, iso é basicamente como calquera matriz funciona,
independentemente de que era un retorno por malloc ou se é a pila.
Calquera matriz é, basicamente, un punteiro para o inicio da matriz,
e despois de calquera operación de matriz, calquera indexación, é só ir en que a matriz dun determinado desprazamento.
>> Polo tanto, cando digo algo así como s [3], o que vai s e contando 3 caracteres dentro
Así, s [3], temos 0, 1, 2, 3, de xeito s [3] vai para referirse a este l.
[Alumno] E nós poderíamos chegar ao mesmo valor, facendo s + 3 e estrela parénteses?
Si
Isto é equivalente a * (S + 3);
e que é para sempre e sempre equivalentes, non importa o que fai.
Vostede non precisa usar a sintaxe de soporte.
Sempre pode usar * (S + 3) sintaxe.
As persoas tenden a gustar da sintaxe soporte, con todo.
[Alumno] Entón, todas as matrices son en realidade só punteiros.
Hai unha lixeira distinción cando digo int x [4]; >> [alumno] Será que crear a memoria?
[Bowden] Isto vai crear 4 ints na pila, de modo xeral 16 bytes.
Vai crear 16 bytes na pila.
X non é almacenada en calquera lugar.
É só un símbolo sobre o inicio da cousa.
Porque declarou a matriz dentro da función,
o que o compilador vai facer é substituír todas as ocorrencias da variable x
co lugar onde se produciu a opción de poñer estes 16 bytes.
Non pode facer iso con char * s porque s é un punteiro real.
Ela é libre para, a continuación, apuntar para outras cousas.
x é unha constante. Vostede non pode apuntar para unha matriz diferente. >> [Alumno] Okay.
Pero esta idea, esta indexación, é o mesmo, independentemente de se tratar dunha matriz tradicional
ou se é un punteiro para algo ou se é un punteiro para unha matriz malloced.
E, de feito, é así equivalente que esa é tamén a mesma cousa.
El realmente só traduce o que está dentro dos corchetes eo que sobrou dos soportes,
engadila los xuntos, e dereferences.
Polo tanto, esta é tan válida como * (S + 3) ou s [3].
[Estudante] Pode ter punteiros ligan con 2-dimensional arrays?
>> É máis difícil. Tradicionalmente, no.
Unha matriz de 2 dimensións é só unha matriz 1-dimensional con algunha sintaxe cómodo
porque cando eu digo int x [3] [3], que é realmente só unha matriz con 9 valores.
E entón cando índice, o compilador sabe o que quero dicir.
Se eu dixer x [1] [2], el sabe que eu quero ir para a segunda liña, polo que vai saltar o primeiro 3,
e entón el quere que a segunda cousa en que, por iso vai recibir un agasallo.
Pero aínda é só unha matriz unidimensional.
E así se eu quería dar un punteiro para esa matriz,
Eu diría int * p = x;
O tipo de x é só -
É tipo dicindo aproximada de x, xa que é só un símbolo e non é unha variable real,
pero é só un int *.
x é só un punteiro para o inicio desta. >> [Alumno] Okay.
E por iso non vou ser capaz de acceder [1] [2].
Eu creo que hai unha sintaxe especial para declarar un punteiro,
algo ridículo como int (* p [-. algo absolutamente ridículo que eu non sei mesmo.
Pero hai unha sintaxe para declarar punteiros como con parénteses e cousas.
Pode até non deixar facer iso.
Eu podería ollar cara atrás, algo que me diga a verdade.
Vou buscalo máis tarde, se hai unha sintaxe para punto. Pero nunca vai velo.
E mesmo a sintaxe é tan arcaico que usalo, as persoas van perplexo.
Matrices multidimensionais son moi raros como ela é.
Está moi ben -
Ben, se está facendo as cousas da matriz non vai ser raro,
pero en C raramente vai utilizar matrices multidimensionais.
Si >> [Alumno] Digamos que ten unha matriz moi longo.
>> Así, na memoria virtual parece ser todos consecutivos,
como os elementos ao lado uns dos outros,
pero na memoria física, sería posible para que isto se separaron? Si >>.
Como a memoria funciona virtuais é só separa -
A unidade de distribución é unha páxina, que tende a ser de 4 kilobytes,
e así, cando un proceso di, hey, eu quero usar esa memoria,
o sistema operativo vai asignar-lle 4 kilobytes para ese pequeno bloque de memoria.
Mesmo se usa só un único byte pouco en todo o bloque de memoria,
o sistema operativo vai dar o total de 4 kilobytes.
Entón, o que isto significa que eu podería ter - digamos que esta é a miña pila.
Esta pila podían ser separados. A miña pila podería ser megabytes e megabytes.
A miña pila pode ser enorme.
Pero a pila en si debe ser dividido en páxinas individuais,
que, se olharmos para acá, digamos que esta é a nosa memoria RAM,
se eu tivera 2 gigabytes de memoria RAM, este é o enderezo real 0 como byte 0 da miña memoria RAM,
e este é de 2 gigabytes todo o camiño ata aquí.
Polo tanto, esta páxina pode corresponder a este bloque aquí.
Esta páxina pode corresponder a este bloque aquí.
Este pode corresponder a este aquí.
Así, o sistema operativo é libre para asignar memoria física
para calquera páxina individual arbitrariamente.
E isto significa que, se isto ocorre fronteira para straddle dunha matriz,
unha matriz pasa a ser deixada deste e dereita da orde dunha páxina,
a continuación, que a matriz vai ser dividida en memoria física.
E entón cando saia do programa, ao final do proceso,
eses mapeamento obter borrado e entón é libre para usar estes pequenos bloques para outras cousas.
Máis preguntas?
[Alumno] aritmética O punteiro. >> Oh yeah.
Cordas foron máis fáciles, pero mirando para algo así como ints,
Entón, de volta para int x [4];
Se isto é unha matriz ou se é un punteiro para unha matriz malloced de 4 números enteiros,
vai ser tratado da mesma maneira.
[Estudante] Entón matrices son na pila?
[Bowden] matrices non son na pila. >> [Alumno] Oh
>> [Bowden] Este tipo de arranxo tende a ser na pila
a menos que declarou na - ignorando variables globais. Non use variables globais.
Dentro dunha función que digo int x [4];
Vai crear un bloque de 4 enteiro na pila para esta matriz.
Pero este malloc (4 * sizeof (int)); está a ir na pila.
Pero tras este punto podo usar X e P en practicamente do mesmo xeito,
Ademais das excepcións que eu dixen antes sobre se pode reatribuir p.
Tecnicamente, as súas dimensións son un pouco diferentes, pero iso é totalmente irrelevante.
Vostede non realmente usar os seus tamaños.
O que eu podería dicir p p [3] = 2; ou x [3] = 2;
Podes usalos en exactamente da mesma maneira.
Así, a aritmética de punteiro agora - Si
[Alumno] Non ten que facer p * se ten os soportes?
Os soportes son unha dereference implícita. Ok >>.
En realidade, tamén o que está dicindo o que pode obter matrices multidimensionais
con punteiros, o que pode facer é algo así como, digamos, int ** pp = malloc (sizeof (int *) * 5);
Eu só vou escribir todo primeiro.
Eu non quería iso.
Okay.
O que eu fixen aquí é - Isto debe ser pp [i].
Así, pp é un enlace a un enlace.
Vostede está mallocing pp, para apuntar para unha matriz de 5 estrelas int.
Así, en memoria que ten sobre a pila PP
Vai apuntar unha matriz de 5 bloques que son todos propios punteiros.
E entón cando malloc aquí, malloc eu que cada un destes indicadores individuais
debería apuntar un bloque separado de 4 bytes na pila.
Polo tanto, este apunta a 4 bytes.
E iso apunta a unha distinta 4 bytes.
>> E todos eles apuntan para as súas propias 4 bytes.
Isto dá-me unha forma de facer as cousas multidimensionais.
Eu podería dicir pp [3] [4], pero agora iso non é a mesma cousa como matrices multidimensionais
porque as matrices multidimensionais é traducido [3] [4] nun único desprazamento para a matriz X.
Este p dereferences, accede a terceira índice, a continuación, que dereferences
e accesos - 4 sería válida - o segundo índice.
Considerando que, cando tivemos a int x [3] [4] antes como unha matriz multidimensional
e cando lle dá un dobre soporte é realmente só dereference unha única
está seguindo un único punteiro e, a continuación, un desprazamento,
iso é realmente referencias 2D.
Vostede segue dous punteiros separados.
Polo tanto, esta tamén tecnicamente permite que teña matrices multidimensionais
onde cada arranxo individuo e tamaños diferentes.
Entón eu creo irregulares matrices multidimensionais é o que se chama
xa que realmente o primeiro que podería apuntar cara algo que ten 10 elementos,
A segunda cousa que podería apuntar cara algo que ten 100 elementos.
[Alumno] Existe un límite para o número de punteiros que pode ter
apuntando a outros punteiros? Non >>
Pode ter int ***** p.
Voltar á aritmética de punteiro - >> [alumno] Oh Si >>.
[Alumno] Se eu tivera int p *** e entón eu fago un dereferencing e digo p * é igual a este valor,
é que só vai facer un nivel de dereferencing? Si >>.
Entón, se eu queira acceder a cousa que o último punteiro está a apuntar cara -
Entón fai p ***. Ok >>.
Polo tanto, este é p apunta a un bloque, apunta a outro bloque, apunta a outro bloque.
Entón, se fai * p = outra cousa, entón está cambiando esta
agora a apuntar cara a un bloque distinto. Ok >>.
>> [Bowden] E estes foron malloced, entón xa se filtrou memoria
a menos que acontecer ter referencias distintas destas
sempre que non pode volver a aquelas que só xogou fóra.
Aritmética de punteiro.
int x [4]; vai reservar unha matriz de 4 enteiros
onde x vai apuntar para o inicio da matriz.
Polo tanto, cando digo algo x [1], quero que signifique ir para o segundo enteiro na matriz,
o que sería un agasallo.
Pero, realmente, que é 4 bytes na matriz dende que este número enteiro ocupa 4 bytes.
Entón, un desprazamento de 1 realmente significa un desprazamento dunha
veces o tamaño de calquera que sexa o tipo de matriz é.
Este é un array de enteiros, para que saiba facer unha veces o tamaño de int cando quere compensar.
A sintaxe outro. Lembre que isto é equivalente a * (x + 1);
Cando digo punteiro + 1, o que que retorna é o enderezo que o punteiro está almacenando
máis 1 veces o tamaño do tipo de punteiro.
Entón, se x = ox100, entón x + 1 = ox104.
E pode abusar dese e dicir algo así como char * c = (char *) x;
e agora c vai ser o mesmo enderezo x.
c vai ser igual a ox100,
pero c + 1 será igual a ox101
desde a aritmética de punteiro depende do tipo de punteiro que está engadindo.
Entón c + 1, que mira para c, é un punteiro char, por iso vai engadir unha veces o tamaño do char,
que sempre vai ser un, para que obteña 101,
mentres que se o fai x, o cal é tamén aínda 100, x + 1 vai ser 104.
[Estudante] Podes usar C + + para avanzar o punteiro por un?
Si, pode.
Vostede non pode facelo con x porque x é só un símbolo, é unha constante, non pode cambiar x.
>> Pero c pasa de ser só un punteiro, entón C + + é perfectamente válido e será incrementado en 1.
Se c fose só un int *, entón c + + sería 104.
+ + Aritmética de punteiro fai exactamente como C + 1 tería feito aritmética de punteiro.
Este é, en realidade, como unha morea de cousas como merge sort -
En vez de crear copias de cousas, pode pasar en vez -
Como se eu quería pasar esta metade da matriz - imos borrar un pouco iso.
Imos dicir que eu quería pasar deste lado da matriz nunha función.
O que eu ía pasar esa función?
Se eu pasar x, eu estou pasando este enderezo.
Pero quero pasar ese enderezo particular. Entón o que debo pasar?
[Estudante] Punteiro + 2?
[Bowden] Entón x + 2. Si
Isto vai ser este enderezo.
Tamén vai moi frecuentemente velo como x [2] e, a continuación, o enderezo do.
Entón, necesitas ter o enderezo dela, porque o soporte é un dereference implícita.
x [2] refírese ao valor que está na caixa, e entón quere o enderezo desa caixa,
entón di & x [2].
Entón é así que algo merge sort onde quere pasar a metade da lista para algo
realmente só pasan & x [2], e agora ata a chamada recursiva está en causa,
miña nova matriz comeza aí.
Última preguntas minutos.
[Alumno] Se non poñer un ou un - que é o que chama? >> Star?
[Alumno] Star. >> Tecnicamente, operador dereference, pero - >> [alumno] Referencia no.
>> Se non poñer unha estrela ou un comercial, o que acontece se eu só dicir y = x e x é un punteiro?
Cal é o tipo de y? >> [Alumno] Eu só vou dicir que é punteiro 2.
Entón, se acaba de dicir y = x, agora x e y punto para o mesmo. >> [Estudante] Punto para a mesma cousa.
E, se x é un punteiro int? Sería >> reclamar, porque non pode asignar punteiros.
[Alumno] Okay.
Lembre que os punteiros, a pesar de atrae-los como flechas,
realmente tenda todos eles - int * x - realmente todo x está almacenando é algo así como ox100,
que acontecer para representar como apuntando para o bloque almacenado a 100.
Polo tanto, cando digo int * y = x, eu só estou copiando ox100 en y,
que está indo só para representar como y, apuntando tamén para ox100.
E se eu dixer int i = (int) X; entón eu vai almacenar calquera que sexa o valor ox100 é
dentro del, pero agora vai ser interpretado como un enteiro, en vez de un punteiro.
Pero precisa do reparto ou entón el vai reclamar.
[Estudante] Entón quere dicir para lanzar -
Será que vai estar lanzando int X ou y int reparto?
[Bowden] O que?
[Alumno] Okay. Tras estes parénteses está alí vai ser un x ou ay alí?
>> [Bowden] De calquera. x e y son equivalentes. >> [Alumno] Okay.
Porque son os dous punteiros. Si >>.
[Estudante] Entón sería almacenar os 100 hexadecimal na forma enteiro? >> [Bowden] Yeah.
Pero non o valor de todo o que apunta.
[Bowden] Yeah. >> [Alumno] Entón, só o enderezo en forma de número enteiro. Okay.
[Bowden] Se quixese, por algunha razón estraña,
podería exclusivamente xestione punteiros e nunca tratar con números enteiros
e só ser como int * x = 0.
Entón, vai estar moi confuso, xa aritmética de punteiro comeza a ocorrer.
Así, os números que almacenan son sen sentido.
É exactamente como acaba interpretala-las.
Entón, eu estou libre para copiar ox100 dun * int para un int,
e eu son libre para asignar - é, probablemente, vai ser repreendidos por non publicar -
Eu son libre para asignar algo (int *) ox1234 neste int * arbitraria.
Entón ox123 é tan enderezo válido de memoria como e y.
& Y pasa para voltar algo que é moi fermoso ox123.
[Alumno] Tería que ser unha forma moi legal para ir hexadecimal para a forma decimal,
Como se ten un punteiro e lanzalo como un int?
[Bowden] Pode realmente só imprimir usando como printf.
Imos dicir que eu teño int y = 100.
Entón printf% (d \ n - como xa debería saber - que imprimir como un enteiro x,%.
Nós só imprimir lo como hexadecimal.
Así, un enlace non é almacenado como hexadecimal,
é un número enteiro non é almacenado como decimal.
Todo é almacenado como binario.
É que tenden a mostrar punteiros como hexadecimal
porque pensamos de cousas neses bloques de 4 bytes,
e enderezos de memoria tenden a ser familiar.
Somos como, se comeza con bf, el pasa a ser na pila.
Entón é só nosa interpretación de punteiros como hexadecimal.
Okay. Calquera dúbida últimos?
>> Eu estarei aquí para un pouco despois, se ten calquera outra cousa.
E ese é o fin de todo.
>> [Alumno] Yay! [Aplausos]
>> [CS50.TV]