Вы находитесь на странице: 1из 39

3/7/2014 Tutorial de Ponteiros e Arrays em C

http://cesarakg.freeshell.org/pointers.html 1/39
TutorialdePonteiroseArraysemC
TedJensen(TraduoCsarA.K.Grossmann)
Prefcio
Agradecimentos
SobreoAutor
UsodesteMaterial
OutrasVersesDesteDocumento
Introduo
1.OQueUmPonteiro?
Referncias
2.TiposPonteiroseArrays
3.PonteiroseStrings
4.MaisSobreStrings
5.PonteiroseEstruturas
6.UmPoucoMaisSobreStrings,eArraysdeStrings
7.MaisSobreArraysMultiDimensionais
8.PonteirosParaArrays
9.PonteiroseAlocaoDinmicadeMemria
Mtodo1
Mtodo2
Mtodo3
Mtodo4
10.PonteirosParaFunes
Referncias
Eplogo
Prefcio
Estedocumentofoifeitocomoumaintroduoaosponteirosparaprogramadoresiniciantesna
linguagemC.DepoisdevriosanosdeleiturasecontribuiesavriasconfernciassobreC,incluindo
asdaFidoNeteUseNet,eunoteiqueumgrandenmerodenovatosnoCparecemterumadificuldade
ementenderosfundamentosdoponteiros.Euresolvientoassumiratarefadetentarexplicaraelesem
umalinguagemsimplesecommuitosexemplos.
Aprimeiraversodestedocumentofoicolocadanodomniopblico,assimcomoesta.Elafoiescolhida
porBobStout,queincluiuomesmocomooarquivoPTRHELP.TXT,emsuacoleolargamente
distribudadeSNIPPETS.Desdeolanamentooriginalem1995,euacrescenteiumaquantia
significativadematerialefizalgumascorreesmenoresaotrabalhooriginal.
NaversoHTML1.1,eufizumpequenonmerodemudanasnaapresentaocomoresultadode
comentriosquerecebiporemaildetodoomundo.Naverso1.2euatualizeiosdoisprimeiros
captulospararefletiramudanadecompiladores16bitsparacompiladores32bitsnosPCs.
Agradecimentos
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 2/39
Existemtantaspessoasquecontribuiramsemsaberaestetrabalho,porcausadasquestesqueeles
colocaramnoFidoNetCEcho,ounoNewsgroupUseNetcomp.lang.c,ouvriasoutrasconferncias
emoutrasredes,queseriaimpossvellistaratodas.AgradecimentosemespecialaBobStout,quefoi
gentilemincluiraprimeiraversodestematerialemseuarquivoSNIPPETS.
SobreoAutor
TedJensenumEngenheiroEletrnicoaposentadoquetrabalhoucomoprojetistadehardwareou
gerentedeprojetistasdehardwarenocampodegravaomagntica.Programaotemsidoumhobby
seudesde1968,quandoeleaprendeuaperfurarcartesparaseremexecutadosemummainframe(o
mainframetinha64Kdememriadencleomagntico!).
UsodesteMaterial
TudoqueestcontidoaquiestliberadoparaoDomnioPblico.Qualquerpessoapodecopiarou
distribuirestematerialdamaneiraquedesejar.Anicacoisaqueeupeoqueseestematerialfor
usadocomoauxlioemumaclass,euapreciariaseelefossedistribudocompleto,ouseja,incluindo
todososcaptulos,prefcioeintroduo.Eutambmapreciariase,nestascircunstncias,oinstrutor
destaclassemeenviasseumanotaemumdosendereosabaixoparameinformardisto.Euescrevieste
materialnaesperanaqueomesmofossetilparaoutrosecomoeunoestoupedindonenhuma
remuneraofinanceira,anicaformadeeusaberqueeuatingipelomenosparcialmentemeuobjetivo
atravsdestefeedbackdosqueacharamestematerialtil.
Apropsito,vocnoprecisaseruminstrutorouprofessorparacontactarme.Euapreciareiumanota
dequalquerumqueacharestematerialtil,ouquetiveralgumacrticaconstrutivaaoferecer.Tambm
estoudispostoaresponderaperguntasenviadasviaemailparaoendereoabaixo.
OutrasVersesDesteDocumento
Almdaversohipertextodestedocumento,eudisponibilizeioutrasversesmaisapropriadaspara
impressoouparadownloaddodocumentocompleto.Sevocestinteresssadoemmanterse
atualizadocommeuprogressonestarea,ouquiserverificarsehversesmaisrecentesdeste
documento,vejameuWevSiteemhttp://www.netcom.com/~tiensen/ptr/cpoint.hm
TedJensen
RedwoodCity,California
tjensen@ix.netcom.com
Feb.2000
Introduo
SevocquerterproficinciaemescrevercdigonalinguagemC,temqueterumbomconhecimento
sobrecomousarponteiros.Infelizmente,osponteirosCparecemrepresentarumobstculoparanovatos,
particularmenteparaosquevemdeoutraslinguagensdecomputador,comoFORTRAN,Pascalou
BASIC.
Paraajudarestesnovatosaentenderponteiroseuescreviomaterialpresente.Paraobteromximo
benefciodestematerial,euachoimportantequeousurioconsigaexecutarocdigodasvriaslistagens
contidasnoartigo.Eutentei,portanto,fazercomquetodoocdigoatendessesnormasANSI,de
formaqueirfuncionarcomqualquercompiladorquetambmatendaasmesmasnormasANSI.Eu
tambmtenteicolocarocdigoemblocosnotexto.Destaforma,comaajudadeumeditordetextos
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 3/39
ASCII,vocpodecopiarumdadoblocodecdigoparaumnovoarquivoecompilaromesmoemseu
sistema.Eurecomendoqueosleitoresfaamistojquevaiajudaraentenderomaterial.
1.OQueUmPonteiro?
UmadascoisasqueosnovatosemCtemdificuldadeoconceitodeponteiros.Oobjetivodestetutorial
fornecerumaintroduoaosponteiroeseoseuusoparaestesnovatos.
Eudescobriqueumadasrazesprincipaisparaosproblemasqueosnovatostemcomponteirosque
elestemumconhecimentofracooumnimosobrevariveis(daformaquesousadasemC).Assim,
vamoscomearadiscussocomasvariveisCemgeral.
Umavarivelemumprogramaalgoquetemumnome,ecujovalorpodevariar.Aformaqueo
compiladoreolinkertratamnasqueelesatribuemumblocoespecficodamemriadocomputador
paraguardarovalordavarivel.Otamanhodoblocodependedointervalodevalorespermitido
varivel.Porexemplo,emumPCde32bits,otamanhodeumavarivelinteger4bytes.Emvelhos
PCsde16bits,era2bytes.EmCotamanhodeumtipodevarivelcomoointeironoprecisasero
mesmoemtodosostiposdemquinas.Almdisto,existemaisdeumtipodevarivelinteiraemC.
Temososintegers,oslongintegers,eosshortintegersquevocvaiencontraremqualquertexto
bsicosobreC.Estedocumentoassumeousodeumsistemade32bitscomintegersde4bytes.
Sevocquisersaberotamanhodosvriostiposdeinteirosnoseusisetma,executeocdigoabaixoque
elelhedarestainformao.
#include <stdio.h>

int main()
{
printf("size of a short is %d\n", sizeof(short));
printf("size of a int is %d\n", sizeof(int));
printf("size of a long is %d\n", sizeof(long));
}
Quandodeclaramosumavarivel,informamosaocompiladorduascoisas,onomedavariveleotipo
damesma.Porexemplo,declaramosumavariveldotipointegercomonomekescrevendo:
int k;
Aoveraparte"int"nestadeclaraoocompiladorreserva4bytesdememria(emumPC)para
guardarovalordointeger.Eletambmmontaumatabeladesmbolos.Nestatabelaeleacrescentao
smbolokeoendereorelativonamemriaemqueestes4bytesforamseparados.
Destaforma,semaistardeescrevemos:
k = 2;
esperamosque,naexecuo,quandoestadeclaraoforexecutada,ovalor2sejacolocadonaporo
dememriareservadaparaguardarovalordek.EmCnosreferimosaumavarivelcomoointegerk
comosendoum"objeto".
Emumcertosentidoexistemdois"valores"associadosaoobjetok.Umovalordointeiroarmazenado
ali(2noexemploacima)eooutroo"valor"dalocalizaodememria,isto,oendereodek.
Algunstextossereferemaestesdoisvaloerscomanomenclaturarvalue(rightvalue,valordireita,
pronunciado"arevalue"),elvalue(leftvalue,valoresquerda,pronunciado"elvalue")
respectivamente.
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 4/39
Emalgumaslinguagens,olvalueovalorquepodeaparecerdoladoesquerdodeumoperadorde
atribuio'='(isto,oenderoparaondeoresultadodaexpressodoladodireitovai).Orvalueoque
estnoladodireitodadeclaraodeatribuio,o2acima.Rvaluesnopodemserusadosnolado
esquerdodadeclaraodeatribuio.Destaforma,2 = k;ilegal.
Naverdade,adefinioacimade"lvalue"foiumpoucomodificadaparaoC.DeacordocomK&RII
(pgina197):[1]
"Anobjectisanamedregionofstorageanlvalueisanexpressionreferringtoanobject."
("Umobjetoumaregiodearmazenamentoquetemnomeumlvalueumaexpressoquerefereum
objeto.")
Entretanto,nesteponto,adefiniooriginalmentecitadaacimasuficiente.Conformenostornamos
maisfamiliarescomponteirosiremosentraremmaisdetalhessobreisto.
Vamosconsideraragora:
int j, k;

k = 2;
j = 7; <-- linha 1
k = j; <-- linha 2
Noexemploacima,ocompiladorinterpretaojnalinha1comsendooendereodavarivelj(seu
lvalue)ecriaocdigoparacopiarovalor7paraaqueleendereo.Nalinha2,entretanto,oj
interpretadocomooseurvalue(jqueestnoladodireitodooperadordeatribuio'=').Ouseja,ao
jserefereaovalorarmazenadonaposiodememriareservadaparaoj,nestecaso,o7.Assim,o7
copiadoparaoendereodesignadopelolvaluek.
Emtodosestesexemplos,estamosuandoinetgersde4bytesdeformaquetodasascpiasdervaluesde
umlocaldearmazenamentoparaoutrofeitopelacpiade4bytes.Seestivssemosusandointeirosde
2bytes,estaramoscopiando2bytes.
Agora,digamosquetemosumarazoparaquererqueumavarivelarmazeneumlvalue(umendereo).
Otamanhonecessrioparaarmazenarestetipodevalordependedosistema.Emcomputadoresdesktop
antigoscom64Kdememriatotal,oendereodequalquerpontonamemriapodeestarcontidoem2
bytes.Computadorescommaismemriavonecessitarmaisbytesparaconterumendereo.Otamanho
realnecessrionotoimportanto,jquetemosumaformadeinformaraocompiladorqueoque
queremosarmazenarumendereo.
Estetipodevarivelchamadodevarivelponteiro(porrazesqueesperamosquefiquemclarasum
poucomaisadiante).EmCquandodefinimosumavarivelponteironsofazemosprecedendooseu
nomecomumasterisco.EmCtambmdamosanossoponteiroumtipoque,nestecaso,refereseao
tipodedadoarmazenadonoendereoqueestaremosarmazenandoemnossoponteiro.Porexemplo,
considereadeclaraodevarivel:
int *ptr;
ptronomedenossavarivel(comokeraonomedenossavarivelinteger).O'*'informaao
compiladorquequeremosumavarivelponteiro,isto,eledeveseparartantosbytesquantosforem
necessriosparaarmazenarumendereonamemria.Ointdizquepretendemosuasrnossavarivel
ponteiroparaarmazenaroendereodeuminteiro.Destetipodeponteirosedizqueele"apontapara"
uminteiro.Entretanto,notequequandoescrevemosint k;,nsnodamosakumvalor.Seesta
definioforfeitaforadequalquerfuno,compiladoresANSIirocolocarnelasovalorinicialzero.
Deformasemelhante,ptrnotemumvalor,jquenoarmazenamosumendereonadeclarao
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 5/39
acima.Nestecaso,novamenteseadeclaraoestiverforadequalquerfuno,elainicializadaparaum
valorquegarantidamentenoapontaparaqualquerobjetoCoufuno.Umponteiroiniciadodesta
formachamadodeponteiro"null".
Opadrodebitsusadoparaumponteironullpodeounoresultaremzerojquedependedosistema
especficonoqualocdigoestsendodesenvolvido.Parafazercomqueocdigofontesejacompatvel
entrevrioscompiladoresemvriossistemas,umamacrousadapararepresentarumponteironull.A
macrorecebeonomeNULL.Assim,colocarovalorNULLemumponteiro,comoemumadeclarao
deatribuio,comoptr = NULL;,garantequeoponteiroumponteironull.Deformasimilar,da
mesmaformaquealgumtestaumvalorinteiroparaversezero,comoemif(k == 0),podemos
testarseumponteironullusandoif(ptr == NULL).
Voltemosaousodenossanovavarivelptr.Suponhaagoraquequeremosarmazenaremptro
endereodenossavarivelinteirak.Paraisto,usamosooperadorunrio&eescrevemos:
ptr = &k;
Oqueooperador&fazrecuperarolvalue(endereo)dek,mesmoquekestejanoladodireitodo
operador'='deatribuio,ecopiaomesmoparaocontedodenossoponteiroptr.Agora,dizsequeptr
"apontapara"k.Continueconoscoagora,hsomentemaisumoperadorqueprecisamosdiscutir.
O"operadordedereferenciamento"oasterisco,eusadoconformeoexemploabaixo:
*ptr = 7;
Estalinhaircopiaro7paraoendereoapontadoporptr.Assim,septr"apontapara"(contmo
endereode)k,adeclaraoacimaircolocaremkovalor7.Ouseja,quandousamoso'*'desta
forma,estamosnosreferindoaovalorparaoqualptrestapontando,noaovalordoponteiroemsi.
Deformasemelhante,podemosescrever:
printf("%d\n", *ptr);
paraescrevernatelaovalorinteiroarmazenadonoendereoapontadoporptr.
Umaformadevertudoistojuntoexecutaroseguinteprogramaeentoervisarocdigoeasada
cuidadosamente.
Programa1.1
/* Program 1.1 from PTRTUT10.TXT 6/10/97 */

#include <stdio.h>

int j, k;
int *ptr;

int main(void)
{
j = 1;
k = 2;
ptr = &k;
printf("\n");
printf("j has the value %d and is stored at %p\n", j, (void *)&j);
printf("k has the value %d and is stored at %p\n", k, (void *)&k);
printf("ptr has the value %p and is stored at %p\n", ptr, (void *)&ptr);
printf("The value of the integer pointed to by ptr is %d\n", *ptr);

return 0;
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 6/39
}
Nota:AindatemosquediscutirosaspectosdeCquerequeremousodaexpresso(void *)usada
acima.Porenquanto,incluaamesmanoseucdigodeteste.Iremosexplicarasrazesportrsdesta
expressomaistarde.
Pararevisar:
Umavariveldeclaradadandoaelaumtipoeumnome(p.ex.,intk)
Umavarivelponteirodeclaradadandoaelaumtipoeumnome(p.ex.,int*ptr)ondeo
asteriscoinformaaocompiladorqueavariveldenomeptrumavarivelponteiroeotipo
informaaocompiladorquetipooponteiroaponta(inteironestecaso).
Umavezqueumavarivelsejadeclarada,podemosobterseuendereoprecedendooseunome
comooperadorunrio&,comoem&k.
Podemos"dereferenciar"umponteiro,isto,referirmosovalorparaoqualeleaponta,usandoo
operadorunrio'*'comoem*ptr.
O"lvalue"deumavarivelovalordeseuendereo,isto,ondeelaestarmazenadana
memria.O"rvalue"deumavarivelovalorarmazenadonaquelavarivel(naqueleendereo).
Referncias
[1]"TheCProgrammingLanguage"2ndEdition
B.KernighanandD.Ritchie
PrenticeHall
ISBN0131103628
2.TiposPonteiroseArrays
Podemosavanaragora.Consideremosqueprecisamosidentificarotipodavarivelparaoqualo
ponteiroaponta,comoem:
int *ptr;
Umarazoparafazeristoquemaistarde,umavezqueptr"apontepara"algumacoisa,se
escrevermos:
*ptr = 2;
ocompiladorsaberquantosbytescopiarparaaquelalocalizaodememriaapontadaporptr.Septr
foideclaradocomoapontandoparauminteiro,4bytesserocopiados.Deformasemelhanteparafloats
edoublesonmeroapropriadosercopiado.Mas,definirotipoparaoqualoponteiroapontapermite
umgrandenmerodeoutrasformasqueocompiladorpodeinterpretarocdigo.Porexemplo,
considereumblocodememriaconsistindoemdezinteirosemlinha.Ouseja,40bytesdememriaso
separadosparaarmazenar10inteiros.
Agora,digamosqueapontamosnossoponteiroptrparaoprimeirodestesinteiros.Mais,vamosdizer
queaqueleinteiroestlocalizadonaposiodememria100(decimal).Oqueacontecequando
escrevemos:
ptr + 1;
Comoocompilador"sabe"quesetratadeumponteiro(isto,seuvalorumendereo),equeest
apontandoparauminteiro(seuendereoatual,100,oendereodeuminteiro),eleacrescenta4aptr,
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 7/39
emvezde1,assimoponteiro"aponta"paraoprximointeiro,naposiodememria104.Deforma
semelhante,ondeoptrdeclaradocomoumponteiroparaumshort,eleseracrescidode2emvezde
1.Omesmovaleparaoutrostiposdedados,comofloats,doubles,oumesmotiposdedadosdefinidos
pelousurio,comoestruturas.Istoobviamentenoomesmotipode"adio"quenormalmente
pensamos.EmC,elareferidacomoadiousando"aritmticadeponteiros",umtermoqueiremos
retornarmaistarde.
Deformasimilar,jque++ptreptr++soequivalentesaptr + 1(apesarqueopontonoprograma
emqueptrsejaincrementadopodeserdiferente),incrementarumponteirousandoooperadorunrio
++,tantoproups,incrementaoendereoqueelearmazenapelaquantidadesizeof(type)onde
"type"otipodeobjetoapontado(isto,4parauminteiro).
Comoumblocode10inteiroslocalizadodeformacontguanamemria,pordefinio,umarrayde
inteiros,temosaumrelacionamentointeressanteentrearrayseponteiros.
Considereoseguinte:
int my_array[] = {1, 23, 17, 4, -5, 100};
Temosaumarraycontendo6inteiros.Nosreferimosacadaumdestesinteirosviaumsubscritoa
my_array,isto,usandomy_array[0]amy_array[5].Maspodemosalternativamenteacesslos
usandoumponteiro,comonoexemploabaixo:
int *ptr;
ptr = &my_array[0]; /* aponta nosso ponteiro para o primeiro
inteiro em nosso array */
Eassimpodemosescrevernossoarrayusandoouanotaodearray,oudereferenciandonosso
ponteiro.Oseguintecdigoilustraisto:
Programa2.1
/* Program 2.1 from PTRTUT10.HTM 6/13/97 */

#include <stdio.h>

int my_array[] = {1,23,17,4,-5,100};
int *ptr;

int main(void)
{
int i;
ptr = &my_array[0]; /* point our pointer to the first
element of the array */
printf("\n\n");
for (i = 0; i < 6; i++)
{
printf("my_array[%d] = %d ",i,my_array[i]); /*<-- A */
printf("ptr + %d = %d\n",i, *(ptr + i)); /*<-- B */
}
return 0;
}
CompileeexecuteoprogramaacimaenotecomcuidadoaslinhasAeBequeoprogramaescreveos
mesmosvaloresemcadacaso.TambmnotecomodereferenciamosnossoponteironalinhaB,isto,
primeiroincrementamoseleeentodereferenciamosonovoponteiro.MudealinhaBpara:
printf("ptr + %d = %d\n", i, *ptr++);
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 8/39
eexecuteoprogramanovamente...entomudepara:
printf("ptr + %d = %d\n", i, *(++ptr));
etentenovamente.Cadaveztentepreveroresultadoeexaminecomcuidadooresultadoreal.
EmC,opadrodeclaraqueondeprecisamosusar&var_name[0],podemostrocarporvar_name,
assim,nonossocdigo,ondeescrevemos:
ptr = &my_array[0];
podemosescrever:
ptr = my_array;
paraobteromesmoresultado.
Porcausadistoquemuitostextossereferemaonomedeumarraycomoumponteiro.Euprefiropensar
que"onomedoarrayoendereodoprimeiroelementodoarray".Muitosiniciantes(inclusiveeu
quandoestavaaprendendo)tematendnciadeficarconfusoaopensarnistocomoumponteiro.Por
exemplo,enquantopodemosescrever
ptr = my_array;
nopodemosescrever
my_array = ptr;
Arazoqueenquantoptrumavarivel,my_arrayumaconstante.Ouseja,olocalondeo
primeiroelementodemy_arrayserarmazenadonopodeseralteradoumavezquemy_array[]tenha
sidodeclarado.
Umpoucoantes,quandodiscutimosotermo"lvalue",euciteiK&R2ondeestdeclarado:
"Anobjectisanamedregionofstorageanlvalueisanexpressionreferringtoanobject".
("Umobjetoumaregiodearmazenamentocomnomeumlvalueumaexpressoquesereferea
umobjeto").
Istolevaaumproblemainteressante.Comomy_arrayumaregiodearmazenamentonomeada,por
qumy_arraynadeclaraoacimanoumlvalue?Pararesolveresteproblema,algunssereferema
my_arraycomosendoum"lvaluenomodificvel".
Modifiqueoprogramaexemploacimatrocando
ptr = &my_array[0];
para
ptr = my_array;
eexecutenovamenteparaverseosresultadossoidnticos.
Agora,vamosnosaprofundarumpoucomaisnadiferenaentreosnomesptremy_arraycomoforam
usadosacima.Algunsautoressereferemaonomedeumarraycomosendoumponteiroconstante.O
queistoquerdizer?Bem,paraentenderotermo"constante"nestesentido,vamosretornarnossa
definiodotermo"varivel".Quandodeclaramosumavarivelnsseparamosumpontonamemria
paraarmazenarovalordotipoapropriado.Umavezqueistofoifeito,onomedavarivelpodeser
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 9/39
interpretadoemumadeduasformas.Quandousadonoladoesquerdodooperadordeatribuio,o
compiladorinterpretacomoolocaldememriaparaoqualmoverovalorresultantedaavaliaodo
termodoladodireitodooperadordeatribuio.Mas,quandousadonoladodireitodooperadorde
atribuio,onomedavarivelinterpretadocomosignificandoocontedoarmazenadonaquele
endereodememria,separadoparaarmazenarovalordaquelavarivel.
Comistoemmente,vamosagoraconsideraramaissimplesdasconstantes,comoem:
int i, k;
i = 2;
Aqui,enquantoiumavariveleentoocupaespaonaporodedicadaaosdadosnamemria,2
umaconstantee,comotal,emvezderecebermemrianosegmentodedados,elaestinserida
diretamentenosegmentodecdigodamemria.Ouseja,enquantoescreveralgocomok = i;dizao
compiladorparacriarcdigoquenaexecuoirprocuraralocalizaodememria&iparadeterminar
ovalorasermovidoparak,ocdigocriadopori = 2;simplementecoloca2nocdigoenoh
refernciasaosegmentodedados.Ouseja,tantokquantoisoobjetos,mas2noumobjeto.
Deformasimilar,noexemploacima,comomy_arrayumaconstante,umavezqueocompilador
estabeleceondeoarrayserarmazenado,ele"sabe"oendereodemy_array[0]eaover:
ptr = my_array;
elesimplesmenteusaesteendereocomoumaconstantenosegmentodecdigoe,portanto,noest
fazendorefernciaaosegmentodedados.
Estepodeserumbommomentoparaexplicarumpoucomaisousodaexpresso(void *)usadano
Programa1.1noCaptulo1.Comojvimos,podemosterponteirosdevriostipos.Atagora
discutimosponteirosparainteiroseponteirosparacaracteres.Noscaptulosseguintesaprenderemos
sobreponteirosaestruturasemesmoponteirosaponteiros.
Tambmaprendemosqueemdiferentessistemasotamanhodeumponteiropodevariar.Damesma
forma,possvelqueotamanhodeumponteiropossavariardependendodotipodeobjetoapontado.
Assim,damesmaformaquecomosinteirosvocpodeterproblemassetentaratribuiruminteirolonga
umavariveldotiposhort,vocpodeterproblemassetentaratribuirvaloresdeponetirosdevriostipos
paravariveisponteirodeoutrostipos.
Paraminimizaresteproblema,oCpermiteponteirosdotipovoid.Podemosdeclararestetipode
ponteiroescrevendo:
void *vptr;
Umponteirovoidumtipodeponteirogenrico.Porexemplo,enquantooCnopermitea
comparaodeumponteirodotipointeirocomumponteirodotipocaracter,porexemplo,qualquerum
delespodesercomparadoaumponteirovoid.Obviamente,comocomoutrasvariveis,castspodemser
usadosparaconverterdeumtipodeponteiroparaoutro,nascircunstnciasapropriadas.NoPrograma
1.1doCaptulo1eufizumcastdosponteirosparainteirosparaponteirosvoidparaqueficassem
compatveiscomaespecificaodeconversode%p.Noscaptulosseguintes,outroscastsserofeitos
porrazesaseremapresentadas.
Bem,foibastantecoisatcnicaparadigerir,eeunoesperoqueuminiciantetentendatudoistona
primeiraleitura.Comotempoeexperinciavocvaivoltarerelerosdoisprimeiroscaptulos.Porora,
vamosavanarparaorelacionamentoentreosponteiros,arraysdecaracter,estrings.
3.PonteiroseStrings
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 10/39
Oestudodestringstilparaentendermaisorelacionamentoentreponteirosearrays.Eletambm
tornafcililustrarcomoalgumasdasfunesstringpadrodoCpodemserimplementadas.Finalmente,
eleilustracomoequandoosponteirospodemedevemserpassadosfunes.
EmC,stringssoarraysdecaracteres.Istononecessariamenteverdadeiroemoutraslinguagens.Em
BASIC,Pascal,FORTRANevriasoutraslinguagens,umastringtemseuprpriotipodedados.Mas
emC,no.EmCumastringqualquerarraydecaracteresterminadocomumcaracterbinriozero
(tambmchamadodenulounulo,escritocomo'\0').Paracomearnossadiscussovamosescrever
algumcdigoque,enquantoservecomoilustrao,vocprovavelmentenuncaescreveralgoparecido
emumprogramareal.Considere,porexemplo:
char my_string[40];

my_string[0] = 'T';
my_string[1] = 'e';
my_string[2] = 'd':
my_string[3] = '\0';
Apesardeningumnuncaescreverumastringdestaforma,oresultadofinalumarraydecaracteres
terminadocomumcaracternul.Pordefinio,emC,umastringumarraydecaracteresterminada
comocaracternul.Perceba,entretanto,que"nul"**no*omesmoque"NULL".'nul'refereseao
zerocomodefinidopelaseqnciadeescape'\0'.Elaocupaumbytedememria.NULL,poroutro
lado,onomedamacrousadaparainiciarponteirosnulos.NULLdefinidopor#defineemum
arquivodecabealhoemseucompiladorC,nulpodenoserdefinidoemlugarnenhum.
Comoescreverocdigoacimapodedemorarbastante,oCpermiteduasformasalternativasdechegar
aomesmofim.Primeiro,podeseescrever:
char my_string[40] = ('T', 'e', 'd', '\0'};
Masistotambmusamaisdigitaodoqueconveniente.Assim,oCpermite:
char my_string[40] = "Ted";
Quandoasaspasduplassousadas,emvezdasaspassimples(ouplicas),comonosexemplos
anteriores,ocaracternul('\0')automaticamenteacrescentadonofimdastring.
Emtodososcasosacima,amesmacoisaacontece.Ocompiladorseparaumblococontguodememria
detamanho40bytesparaguardaroscaractereseiniciaomesmodeformaqueos4primeiroscaracteres
soTed\0.
Agora,considereoseguinteprograma:
Programa3.1
/* Program 3.1 from PTRTUT10.HTM 6/13/97 */

#include <stdio.h>

char strA[80] = "A string to be used for demonstration purposes";
char strB[80];

int main(void)
{

char *pA; /* a pointer to type character */
char *pB; /* another pointer to type character */
puts(strA); /* show string A */
pA = strA; /* point pA at string A */
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 11/39
puts(pA); /* show what pA is pointing to */
pB = strB; /* point pB at string B */
putchar('\n'); /* move down one line on the screen */
while(*pA != '\0') /* line A (see text) */
{
*pB++ = *pA++; /* line B (see text) */
}
*pB = '\0'; /* line C (see text) */
puts(strB); /* show strB on screen */
return 0;
}
Noexemploacimacomeamosdefinindodoisarraysdecaracteresde80caracterescada.Comoelesso
definidosglobalmente,elessoinicializadoscom'\0'sprimeiro.EntostrAtemos42primeiros
caracteresinicializadosparaastringentreaspas.
Agora,avanandonocdigo,declaramosdoisponteirosdecaracteremostramosastringnatela.Ento
"apontamos"oponteiropAparastrA.Isto,viaadeclaraodeatribuionscopiamosoendereo
destrA[0]emnossavarivelpA.Agorausamosputs()paramostraroqueestapontadoporpAna
tela.Considereaquiqueoprottipodafunoputs():
int puts(const char *s);
Porenquato,ignoreoconst.Oparmetropassadoaputs()umponteiro,ouseja,ovalordeum
ponteiro(jquetodososparmetrosemCsopassadosporvalor),eovalordeumponteiroo
endereoparaoqualeleestapontando,ou,simplesmente,umendereo.Assim,quandoescrevemos
puts(strA)comovimosantes,estamospassandooendereodestrA[0].
Deformasimilar,quandoescrevemosputs(pA)estamospassandoomesmoendereo,jquefizemos
pA = strA;
Istoposto,seguimosocdigoatadeclaraowhile()nalinhaA.AlinhaAdeclara:
EnquantoocaracterapontadoporpA(isto,*pA)noforumcaracternul(isto,oterminador'\0'),
fazemososeguinte:
AlinhaBdeclara:copieocaracterapontadoporpAparaoespaoapontadoporpB,entoincremente
pA,deformaqueaponteparaoprximocaracterepBaponteparaoprximoespao.
Quandocopiamosoltimocaracter,pAapontaagoraparaocaracterdeterminaonuleolao
termina.Entretanto,nocopiamosocaracternul.E,pordefinioumastringemCdeveserterminada
porumnul.Assim,nsacrescentamosocaracternulcomalinhaC.
bastanteeducacionalexecutaresteprogramacomseudepuradoraomesmotempoqueexaminastrA,
strB,pAepBeandandopassoapassopeloprograma.Eatmaiseducacionalseemvezde
simplesmentedefinirstrB[]comofoifeitoacima,colocarmosumvalorinicialcomo:
strB[80] = "1234567890123456789012345678901234567890";
ondeonmerodedgitosusadosejamaiorqueocomprimentodestrAeentorepetiroprocedimento
deseguirpassoapassooprogramaaomesmotempoqueexaminaasvariveisacima.Faaesta
experincia!
Voltandoaoprottipodeputs()porummomento,o"const"usadocomoummodificadorde
parmetrosqueinformaaousurioqueafunonoirmodificarastringapontadapors,isto,astring
sertratadacomoumaconstante.
Obviamente,oqueoprogramaacimailustraumaformasimplesdecopiarumastring.Apsbrincar
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 12/39
comocdigoacimaatterumbomentendimentodoqueestacontecendo,podemosseguircoma
criaodenossoprpriosubstitutoparaostrcpy()quevemcomoC.Elepodeficarassim:
char *my_strcpy(char *destination, char *source)
{
char *p = destination;
while (*source != '\0')
{
*p++ = *source++;
}
*p = '\0';
return destination;
}
Nestecaso,euseguiaprticausadanarotinapadroqueretornarumponteiroparaodestino.
Novamente,afunoprojetadaparaaceitarosvaloresdedoisponteirosdecaracteres,isto,
endereos,eassimnoprogramaanteriorpodemosescrever:
int main(void)
{
my_strcpy(strB, strA);
puts(strB);
}
EumudeiumpoucodaformausadanoCpadroqueteriaoprottipo:
char *my_strcpy(char *destination, const char *source);
Aqui,omodificador"const"usadoparagarantiraousurioqueafunonomodificarocontedo
apontadopeloponteiroorigem.Vocpodeprovaristomodificandoafunoacima,eseuprottipo,
paraincluiromodificador"const"comomostrado.Ento,dentordafunovocpodeacerscentaruma
declaraoquetentemudarocontedodoqueapontadopelafonte,comoem:
*source = 'X';
quenormalmentemudariaoprimeirocaracterdastringparaumX.Omodificadorconstdevefazerque
seucompiladoraponteistocomoumerro.Tenteeveja.
Agora,vamosconsideraralgumasdascoisasqueosexemplosacimanosmostraram.Primeiro,considere
ofatoque*ptr++deveserinterpretadocomoretornandoovalorapontadoporptreemseguida
incrementandoovalordoponteiro.Istotemavercomaprecednciadeoperadores.Ondeescrevemos
(*ptr)++nsincrementaremos,nooponteiro,masoqueoponteiroaponta!Isto,seusadono
primeirocaracterdastringexemploo'T'seriaincrementadoparaum'U'.Vocpodeescreverumcdigo
exemplosimplesparailustraristo.
Lembrenovamentequeumastringnadamaisqueumarraydecaracteres,comoltimocaractersendo
um'\0'.Oquefizemosacimatratarcomacpiadeumarray.Aconteceuserumarraydecaracteres,
masatcnicapodeseraplicadaaumarraydeinteiros,doubles,etc.Naquelescasos,entretanto,no
estaremostratandocomstringseportantoofimdoarraynosermarcadocomumvalorespecialcomo
ocaracternulo.Podemosimplementarumaversoquedependadeumvalorespecialparaidentificaro
fim.Porexemplo,podemoscopiarumaraydeinteirospositivosmarcandoofimcomuminteiro
negativo.Poroutrolado,maisusualquequandoescrevermosumafunoparacopiarumarrayde
itensquenostrings,passemosparaafunoonmerodeitensaseremcopiadosbemcomooendereo
doarray,porexemplo,algocomooindicadopeloprottipoabaixo:
void int_copy(int *ptrA, int *ptrB, int nbr);
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 13/39
ondenbronmerodeinteirosaseremcopiados.Vocpodequererbrincarcomestaidiaecriarum
arraydeinteiroseverseconsegueescreverafunoint_copy()efazlafuncionar.
Istopermiteusarfunesparatratararraysgrandes.Porexemplo,setemosumarrayde5000inteiros
quequeremosmanipularcomumafuno,precisamospassarparaafunosoendereodoarray(e
qualquerinformaoauxiliarcomoonbracima,dependendodoqueestamosfazendo).Oarrayemsi
nopassado,isto,oarrayinteironocopiadoecolocadonapilhaantesdochamadofuno,s
seuendereoenviado.
Istodiferentedepassar,porexemplo,uminteiroaumafuno.Quandopassamosuminteirofazemos
umacpiadointeiro,isto,oseuvalorobtidoecolocadonapilha.Dentrodafunoqualquer
manipulaodovalorpassadonopodeafetardeformaalgumaovalororiginal.Mas,comarrayse
ponteirospodemospassaroendereodavarivele,portanto,manipularosvaloresdasvariveis
originais.
4.MaisSobreStrings
Bem,progredimosumbomtantoemtopoucotempo!Vamosolharparatrsumpoucoeveroquefoi
feitonoCaptulo3,sobrecpiasdeStrings,masemumaluzdiferente.Considereaseguintefuno:
char *my_strcpy(char dest[], char source[])
{
int i = 0;
while (source[i] != '\0')
{
dest[i] = source[i];
i++;
}
dest[i] = '\0';
return dest;
}
Lembrequestringssoarraysdecaracteres.Aquiescolhemosusaranotaodearrayemvezde
notaodeponteirosparafazeracpia.Oresultadoomesmo,isto,astringcopiadausandoesta
notaotocorretoquantoantes.Istolevantaalgunspontosinteressantesparadiscusso.
Comoosparmetrossopassadosporvalor,tantonopassaroponteirocaracterouonomedoarray,
comonoexemploacima,oquerealmentepassadooendereodoprimeiroelementodecadaarray.
Assim,ovalornumricodoparmetroomesmo,casousemosumponteirodecaracterouumnomede
arraycomoparmetro.Istopareceimplicarquedealgumaformasource[i]omesmoque*(p+i).
Defato,istoverdadeiro,isto,ondeestescritoa[i]podesesubstituircom*(a+i)semqualquer
problema.Defato,ocompiladorircriaromesmocdigoemqualquerdoscasos.Assimnosvemosque
aaritmticadeponteiroamesmacoisaqueaindexaodearray.Qualquerumadasduassintaxes
produzomesmoresultado.
IstoNOquerdizerqueponteirosearrayssoamesmacoisa,elesnoso.Estamosapenasdizendo
queparaidentificarumdadoelementoemumarraytemosaescolhadeduassintaxes,umausando
indexaodearrayeoutrausandoaritmticadeponteiros,oquedresultadosidnticos.
Agora,olhandoparaaltimaexpresso,partedela,(a+i),umasimplesadiousandoooperador+e
asregrasdoCdizemqueestaexpressocomutativa.Ouseja,(a+i)idnticoa(i+a).Assim,podemos
escrever*(i+a)comamesmafacilidadequeescrevemos*(a+i).
Mas*(i+a)poderiavirdei[a]!Distodecorreacuriosaverdadeque,se:
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 14/39
char a[20];
int i;
escrever
a[3] = 'x';
omesmoqueescrever
3[a] = 'x';
Tente!Crieumarraydecaracteres,inteirosoulongs,etc.eatribuaaoterceiroouquartoelementoum
valorusandoaabordagemconvencionaleentoescrevaovalorparatercertezaqueestfuncionando.
Entorevertaanotaodearraycomofoifeitoacima.Umbomcompiladornovaireclamareos
resultadosseroidnticos.Umacuriosidade...nadamais!
Agora,olhandoparanossafunoacima,quandoescrevemos:
dest[i] = source[i];
defidoaofatoqueaindexaodearrayeaaritmticadeponteirodosmesmosresultados,podemos
escreveristocomo:
*(dest + i) = *(source + i);
Masistotoma2adiesparacadavalordei.Adies,falandoemtermosgerais,tomammaistempoque
incrementos(comoosfeitosusandoooperador++,comoemi++).Istopodenoserverdadeem
compiladoresmodernoscomotimizao,masnosepodetercerteza.Assim,aversodeponteiropode
serumpoucomaisrpidaqueaversodearray.
Outraformadetornarmaisrpidaaversodeponteiroseriamudar:
while (*source != '\0')
parasimplesmente
while (*source)
jqueovalorentreparntesisirresultaremzero(FALSE)nomesmomomentoemcadaumdoscasos.
Nestepontovocpodequererexperimentarumpoucoescrevendoseusprpriosprogramasusando
ponteiros.Amanipulaodestringsumbomlugarparaexperimentar.Vocpodequererescreversua
prpriaversodefunespadrocomo:
strlen();
strcat();
strchr();
equaisqueroutrasquevocpossateremseusistema.
Voltaremosasstringsesuamanipulaoviaponteirosemumoutrocaptulo.Porenquanto,vamos
mudarediscutirumpoucodeestruturas.
5.PonteiroseEstruturas
Comovocsabe,podemosdeclararaformadeumblocodedadoscontendodiferentestiposdedados
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 15/39
viaumadeclaraodeestrutura.Porexemplo,umarquivodepessoalpodeconterestruturasquese
pareamcomalgoassim:
struct tag {
char lname[20]; /* ltimo nome */
char fname[20]; /* primeiro nome */
int age; /* idade */
float rate; /* p. ex. 12.75 por hora */
};
Digamosquetemosumpunhadodestasestruturasemumarquivoemdiscoequeremoslercadaumae
escreveroprimeiroeltimonomesdecadaumdeformaquetenhamosumalistadaspessoasemnossos
arquivos.Asinformaesrestantesnodevemserescritas.Faremosistoescrevendocomumachamada
defunoepassandoparaaquelaumoumponteiroparaaestruturamo.Parademonstraoeuirei
usarsomenteumaestrutura,maspercebaqueoobjetivoaquiescreverafuno,noaleiturado
arquivoque,presumivelmente,nssabemoscomofazer.
Parareviso,lembrequepodemosacessarmembrosdeestruturascomooperadorponto,comoem:
Programa5.1
/* Program 5.1 from PTRTUT10.HTM 6/13/97 */


#include <stdio.h>
#include <string.h>

struct tag {
char lname[20]; /* last name */
char fname[20]; /* first name */
int age; /* age */
float rate; /* e.g. 12.75 per hour */
};

struct tag my_struct; /* declare the structure my_struct */

int main(void)
{
strcpy(my_struct.lname,"Jensen");
strcpy(my_struct.fname,"Ted");
printf("\n%s ",my_struct.fname);
printf("%s\n",my_struct.lname);
return 0;
}
Agora,estaestruturaemparticularbempequenacomparadacommuitasusadasemprogramasC.Aos
dadosacimaqueremosacrescentar:
date_of_hire; (data types not shown)
date_of_last_raise;
last_percent_increase;
emergency_phone;
medical_plan;
Social_S_Nbr;
etc.....
Setemosumgrandenmerodeempregados,oquequerermosmanipularosdadosnestasestruturas
atravsdefunes.Porexemplo,podemosquererqueumafunoescrevaonomedoempregado
listadoemqualquerestruturapassadaaomesmo.Entretanto,noCoriginal(Kernighan&Ritchie,1st
Edition)noerapossvelpassarumaestrutura,somenteumponteiroparaumaestruturapodiaser
passado.EmANSIC,permitidopassaraestruturacompleta.Mas,comonossoobjetivoaqui
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 16/39
aprendermaissobreponteiros,noiremosfazeristo.
Dequalquerforma,sepassamosaestruturatodaistosignificaqueteremosdecopiartodoocontedoda
estruturadafunoqueestfazendoachamadaparaafunochamada.Emsistemasqueusampilha,
istofeitoempurrandoocontedodaestruturaparaapilha.Comestruturasenormesistopodeserum
problema.Entretanto,passarumponteirousaummnimodoespaodapilha.
Dequalquerforma,comoestaumadiscussosobreponteiros,iremosdiscutircomopassarum
ponteirodedeestruturaecomouslodentrodeumafuno.
Considereocasodescrito,ouseja,queremosumafunoqueiraceitarcomoparmetroumponteiro
paraumaestruturaequedentrodaquelafunoqueremosacessarosmembrosdaestrutura.Por
exemplo,queremosescreveronomedoempregadoemnossaestruturaexemplo.
Certo,agorasabemosquenossoponteiroirapontarparaumaestruturadeclaradausandostructtag.
Declaramosumponteirodestescomadeclarao:
struct tag *str_ptr;
eapontamosparaanossaestruturaexemplocom:
st_ptr = &my_struct;
Agora,podemosacessarumdadomembrodereferenciandooponteiro.Mas,comonsdereferenciamos
oponteiroaumaestrutura?Bem,considereofatoquepodemosquererusaroponteiroparamudara
idadedoempregado.Poderamosescrever:
(*str_ptr).age = 63;
Olheestalinhacomcuidado.Eladiz,substituaoqueestentreparntesispeloquest_ptrest
apontando,queaestruturamy_struct.Assim,istofazomesmoquemy_struct.age.
Entretanto,estaexpressousadacomumacertafreqncia,eosprojetistasdeCcriaramumasintaxe
alternativacomomesmosignificadoque:
st_ptr->age = 63;
Comistoemmente,olheparaoseguinteprograma:
Programa5.2
/* Program 5.2 from PTRTUT10.HTM 6/13/97 */

#include <stdio.h>
#include <string.h>

struct tag{ /* the structure type */
char lname[20]; /* last name */
char fname[20]; /* first name */
int age; /* age */
float rate; /* e.g. 12.75 per hour */
};

struct tag my_struct; /* define the structure */
void show_name(struct tag *p); /* function prototype */

int main(void)
{
struct tag *st_ptr; /* a pointer to a structure */
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 17/39
st_ptr = &my_struct; /* point the pointer to my_struct */
strcpy(my_struct.lname,"Jensen");
strcpy(my_struct.fname,"Ted");
printf("\n%s ",my_struct.fname);
printf("%s\n",my_struct.lname);
my_struct.age = 63;
show_name(st_ptr); /* pass the pointer */
return 0;
}

void show_name(struct tag *p)
{
printf("\n%s ", p->fname); /* p points to a structure */
printf("%s ", p->lname);
printf("%d\n", p->age);
}
Novamente,bastanteinformaoparaserabsorvidadeumasvez.Oleitordevecompilareexecutar
osvriostrechosdecdigoeusandoumdepuradormonitarcoisascomomy_structepenquanto
executapassoapassomaineseguindoocdigoatparadentrodocdigodafunoparaveroque
estacontecendo.
6.UmPoucoMaisSobreStrings,eArraysde
Strings
Bem,vamosvoltarumpoucosstrings.Nadiscussoquesesegue,todasasatribuiesdevemser
entendidascomosendoglobais,ouseja,feitasforadequalquerfuno,incluindomain().
Nsapontamosemumcaptuloanteriorquepodemosescrever:
char my_string[40] = "Ted";
oqueiralocarespaoparaumarrayde40bytesecolocarastringnosprimeiros4bytes(trsparaos
caracteresentreaspaseoquartoparaguardaroterminador'\0').
Naverdade,setudooquequisssemoseraarmazenaronome"Ted"poderamosterescrito:
char my_name[] = "Ted";
eocompiladorcontariaoscaracteres,deixariaespaoparaocaracternulearmazenarotodaldequatro
caracteresnaposiodememriaqueseriaretornadapelonomedoarray,nestecaso,my_name
Emalgunscdigos,emvezdoacima,vocpodever:
char *my_name = "Ted";
queaabordagemalternativa.Existeumadiferenaentreelas?Aresposta...sim.Usandoanotao
dearray4bytesdearmazenamentonoblocodememriaestticaseparado,umparacadacaractere
umparaocaracternulterminador.Masnanotaodeponteiroosmesmos4bytessorequeridos,mais
Nbytesparaarmazenaravarivelponteiromy_name(ondeNdependedosistema,masusualmente
ummnimode2bytesepodeser4oumais).
Nanotaoarary,my_nameumaabreviaopara&my_name[0]queoendereodoprimeiro
elementodoarray.Comoalocalizaodoarrayfixoduranteotempodeexecuo,estauma
constante(enoumavarivel).Nanotaodeponteiro,my_nameumavarivel.Sobrequalomelhor
mtodo,istodependedoquevocvaifazernorestodoprograma.
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 18/39
Avancemosumpassoadianteeconsideremosoqueacontecesecadaumadestasdeclaraesfeita
dentrodeumafunoemvezdeserfeitaglobalmente,foradoslimitesdequalquerfuno.
void my_function_A(char *ptr)
{
char a[] = "ABCDE"
.
.
}


void my_function_B(char *ptr)
{
char *cp = "FGHIJ"
.
.
}
Nocasodemy_function_A,ocontedo,ouvalor(es)doarraya[]consideradocomosendoosdados.
OarrayditocomotendoinicialmenteosvaloresABCDE.NOcasodemy_function_Bovalordo
ponteirocpconsideradocomosendoodado.OponteiroinicialmenteapontaparaastringFGHIJ.
Tantoemmy_function_Aemy_function_Basdefiniessovariveislocaiseassimastring
ABCDEarmazenadanapilha,bemcomoovalordoponteirocp.AstringFGHIJpodeser
armazenadaemqualquerlugar.Emmeusistemaelaarmazenadanosegmentodedados.
Apropsito,ainicializaodevariveisautomticasdearraycomoeufizemmy_function_Aseria
ilegalnovelhoK&RCesomente"amadureceu"nomaisrecenteANSIC.Umfatoquepodeser
importantequandoseconsideraportabilidadeecompatibilidaderetroativa.
Comoestamosdiscutindoorelacionamento/diferenasentreponteirosearrays,vamosdarumaolhada
emarraysmultidimensionais.Considere,porexemplo,oarray:
char multi[5][10];
Oqueistosignifica?Bem,vamosconsiderardaseguinteforma.
char multi[5][10];
Vamospegarapartesublinhadacomosefosseo"nome"deumarray.Entocolocandoantesaparte
chareapsacrescentarmosaparte[10],nsetmosumarrayde10caracteres.Masonomemulti[5]
porsisumarrayindicandoqueexistem5elementos,cadaumdelessendoumarrayde10caracteres.
Assimnstemosumarrayde5arraysde10caracterescada.
Assumindoquetenhamospreenchidoestearraybidimensionalcomdadosdealgumtipo.Namemria,
elepodeparecercomotendosidoformadopelainicializaode5arraysseparados,usandoalgocomo:
multi[0] = {'0','1','2','3','4','5','6','7','8','9'}
multi[1] = {'a','b','c','d','e','f','g','h','i','j'}
multi[2] = {'A','B','C','D','E','F','G','H','I','J'}
multi[3] = {'9','8','7','6','5','4','3','2','1','0'}
multi[4] = {'J','I','H','G','F','E','D','C','B','A'}
Aomesmotempo,elementosindividuaispodemserendereadosusandoasintaxe:
multi[0][3] = '3';
multi[1][7] = 'h';
multi[4][0] = 'J';
Comoosarrayssocontguosnamemria,nossoblocodememriaparaamatrizacimapodeseralgo
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 19/39
dotipo:
0123456789abcdefghijABCDEFGHIJ9876543210JIHGFEDCBA
^
|_____ starting at the address &multi[0][0]
Notequeeunoescrevimulti[0]="0123456789".Seeutivessefeitoisto,umterminador'\0'seria
acrescentadoaoscaracterscontidosentreaspas.Seriaesteocasoseeutivesseseparadoespaopara11
caracteresporlinhaemvezde10.
Meuobjetivoacimailustrarcomoamemriaarranjadaparaarraysdeduasdimenses.Ouseja,este
umarraybidimensionaldecaracteres,NOumarrayde"strings".
Agora,ocompiladorsabequantascolunasestopresentesnoarraydeformaqueelepodeinterpretar
multi+1comooendereodo'a'nasegundalinhaacima.Ouseja,eleacrescenta10,onmerode
colunas,paraobtersuaposio.Seestivermoslidandocominteiroseumarraycomamesmadimenso
ocompiladoracrescentaria10*sizeof(int)que,emminhamquina,seria20.Assim,oendereode9na
quartalinhaacimaseria&multi[3][0]ou(multi+3)emnotaodeponteiro.Paraobterocontedodo
segundoelementonaquartalinhansacrescentaramos1aseuendereoedereferenciaramoso
resultadocomoem
*(*(multi + 3) + 1)
Comumpoucoderaciocnio,podemosverque:
*(*(multi + row) + col) e
multi[row][col] do o mesmo resultado.
Oprogramaseguinteilustraistousandoarraysdeinteirosemvezdearraysdecaracteres.
Programa6.1
/* Program 6.1 from PTRTUT10.HTM 6/13/97*/

#include <stdio.h>
#define ROWS 5
#define COLS 10

int multi[ROWS][COLS];

int main(void)
{
int row, col;
for (row = 0; row < ROWS; row++)
{
for (col = 0; col < COLS; col++)
{
multi[row][col] = row*col;
}
}

for (row = 0; row < ROWS; row++)
{
for (col = 0; col < COLS; col++)
{
printf("\n%d ",multi[row][col]);
printf("%d ",*(*(multi + row) + col));
}
}

return 0;
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 20/39
}
Porcausadadupladerefernciaexigidanaversocomponteiros,onomedeumarraybidimensional
geralmenteditocomosendooequivalenteaumponteiroparaponteiro.Comumarraytridimensional
nsestaramoslidandocomumarraydearraysdearraysealgunsdiriamqueseunomeseriao
equivaletneaumponteiroparaponteiroparaponteiro.Entretanto,nsaquiseparamosumblocode
memriainicialmenteparaoarrayusandoanotaodearray.Portanto,estamoslidandocomuma
constante,noumavarivel.Ouseja,estamosfalandosobreumendereofixo,enoumavarivel
ponteiro.Afunodederefernciausadaacimapermitequeacessemosqualquerelementonoarrayde
arrayssemprecisarmudarovalordaqueleendereo(oendereodemulti[0][0]comodadopelosmbolo
multi).
7.MaisSobreArraysMultiDimensionais
Nocaptuloanteriornsnotamosque,dado
#define ROWS 5
#define COLS 10

int multi[ROWS][COLS];
nspodemosacessaroselementosindividuaisdoarraymultiusandoou
multi[row][col]
ou
*(*(multi + row) + col)
Paraentendermelhoroqueestacontecendo,vamostrocar
*(multi + row)
porXcomoem
*(X + col)
Agora,apartirdistonsvemosqueoXfuncionacomoumponteiro,jqueaexpressode
referenciadaesabemosquecoluminteiro.Aquiaaritmticausadaumtipoespecial,chamada
"aritmticadeponteiros".Istosignificaque,comoestamosfalandodeumarraydeinteiros,oendereo
apontadopor(ouseja,pelovalorde)X+col+1devesermaiorqueoendereoX+colporuma
quantiaigualasizeof(int).
Comoconhecemosoleiautedamemriaparaarraysdeduasdimenses,podemosdeterminarquena
expressomulti+rowcomoausadaacima,multi+row+1deveincrementardevalorumaquantia
igualnecessriapara"apontarpara"aprximalinha,quenestecasodeveserumaquantiaiguala
COLS*sizeof(int).
Istodizqueseaexpresso*(*(multi + row) + col)deveseravaliadacorretamentenaexecuo,o
compiladordevegerarocdigoqueleveemconsideraoovalordeCOLS,isto,asegunda
dimenso.Devidoequivalnciadasduasformasdeexpresso,istoverdadeiroquerestejamosusando
aexpressocomponteiroscomoaqui,ouaexpressodearraymulti[row][col].
Assim,paracalcularqualquerdasexpresses,umtotalde5valoresdevemserconhecidos:
1. Oendereodoprimeiroelementodoarray,queretornadopelaexpressomulti,isto,onome
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 21/39
doarray.
2. Otamanhodotipodeelementosdoarray,nestecaso,sizeof(int).
3. Asegundadimensodoarray.
4. Ovalordondicedaprimeiradimenso,rownestecaso.
5. Ovalordondicedasegundadimenso,colnestecaso.
Dadotudoisto,considereoproblemadedesignarumafunoparamanipularosvaloresdeelementos
deumarraypreviamentedeclarado.Porexemplo,podesecolocaremtodososelementosdoarraymulti
ovalor1.
void set_value(int m_array[][COLS])
{
int row, col;
for (row = 0; row < ROWS; row++)
{
for (col = 0; col < COLS; col++)
{
m_array[row][col] = 1;
}
}
}
Eparachamarestafunousaramos:
set_value(multi);
Agora,apartirdafunonsusamososvaloresqueforamdefinidosvia#definecomoROWSe
COLSqueestabelecemoslimitesparaoslaos.Masestes#definesoapenasconstantesnoquetange
aocompilador,isto,nohnadaqueconecteestesnmerosaotamanhodoarraydentrodafuno.
rowecolsovariveislocais,obviamente.Adefinioformaldeparmetrospermitequeocompilador
determineascaractersticasassociadascomovalordoponteiroqueserpassadoemtempodeexecuo.
Nsrealmentenoprecisamosaprimeiradimensoe,comoveremosmaistarde,existemocasiesonde
iremosperferirnodefinlosdentrodadefiniodeparmetro,foraohbitoouconsistncia,euno
useiaqui.Masasegundadimensodeveserusadaefoivistanaexpressoparaoparmetro.Arazo
porqueprecisamosdelapararesolverm_array[row][col]jfoidescrita.Enquantooparmetrodefineo
tipodedados(intnestecaso)easvariveisautomticasparalinhaecolunasodefinidasnoslaos,
somenteumvalorpodoeserpassadousandoumnicoparmetro.Nestecaso,ovalordemulticomo
notadonadeclaraodechamada,isto,oendereodoprimeiroelemento,geralmentereferidocomo
sendoumponteiroparaoarray.Assim,anicaformaquetemosdeinformarocompiladordasegunda
dimensoincluindoaexplicitamentenadefiniodoparmetro.
Defato,emgeraltodasasdimensesdeordemmaiorqueumsonecessriasquandosetratadearrays
multidimensionais.Ouseja,seestamosfalandodearraysde3dimenses,asegundaeterceira
dimensesdevemserespecificadasnadefiniodoparmetro.
8.PonteirosParaArrays
Ponteiros,obviamente,podemser"apontados"paraqualquertipodeobjetodedado,incluindoarrays.
Enquantoeraevidentequandodiscutamosoprograma3.1,importanteexpandirsobrecomofazeristo
quandosetratadearraysmultidimensionais.
Pararevisar,noCaptulo2nsdeclaramosquedadoumarraydeinteirosnspodemosapontaraum
ponteirodeinteirodaquelearrayusando:
int *ptr;
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 22/39
ptr = &my_array[0]; /* aponta nosso ponteiro para o primeiro
inteiro em nosso array */
Comodeclaramosl,otipodavarivelponteirodeveseromesmotipodoprimeiroelementodoarray.
Almdisto,podemosusarumponteirocomoparmetroformaldeumafunoqueprojetadapara
manipularumarray,porexemplo.
Dado:
int array[3] = {'1', '5', '7'}/
void a_func(int *p);
Algunsprogramadorespodempreferirescreveroprottipodafunocomo:
void a_func(int p[]);
oqueinformaaoutrosquepoderousarestafunoqueamesmafeitaparatrataroselementosdeum
array.Obviamente,emqualquerdoscasos,oquerealmentepassadoovalordeumponteiroparao
primeiroelementodoarray,independentedequenotaousadanoprottipodafunooudefinio.
Notequeseanotaodearrayusada,nohnecessidadedepassaradimensodoarrayjqueno
estamospassandooarrayinteiro,apenasoendereodoprimeiroelemento.
Voltemosagoraaoproblemadoarrayde2dimenses.Comofoiditonocaptuloanterior,oCinterpreta
umarraybidimensionalcomoumarraydearraysdeumasdimenso.Sendoesteocaso,oprimeiro
elementodeumarraybidimensionaldeinteirosumarraydeumadimensodeinteiros.Eumponteiro
paraumarraybidimensionaldeinteirosdeveserumponteiroparaaqueletipodedados.Umaformade
conseguiristoatravsdousodapalavrachave"typedef".Otypedefatribuiumnovonomeaum
tipodedadosespecificado.Porexemplo:
typedef unsigned char byte;
fazcomqueonomebytesignifiqueotipounsignedchar.Portanto
byte b[10];
serumarraydeunsignedchar.
Notequenadeclaraotypedef,apalavrabytefoisubstitudapeloquenormalmenteseriaonomede
nossounsignedchar.Ouseja,aregraparausartypedefqueonovonomeparaotipodedadoso
nomeusadonadefiniodotipodedado.Assim,em:
typedef int Array[10];
Arraytornaseumtipodedadosparaumarrayde10inteiros,isto,Arraymy_arrdeclaramy_arr
comosendoumarrayde10inteiroseArrayarr2d[5]criaarr2dcomoumarrayde5arraysde10
inteiroscada.
NotequeArray*pldfazdepldumponteiroparaumarrayde10inteiros.Como*pldapontaparao
mesmotipodearr2d,atribuiroendereodoarraybidimensionalarr2dpara**pld*,oponteiroao
arraydeumadimensode10inteiros,aceitvel.Isto,pld = &arr2d[0];oupld = arr2d;esto
corretos.
Comootipodedadosqueusamosparanossoponteiroumarrayde10inteiros,deveremosesperarque
incrementarpldpor1irmudarseuvalorde10*sizeof(int),queoqueacontece.Ouseja,sizeof(*pld)
20.Vocpodeprovaristoparavocmesmoescrevendoerodandoumpequenoesimplesprograma.
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 23/39
Agora,enquantousartypedeftornaascoisasmaisclarasparaoleitoremaisfceisparaoprogramador,
istorealmentenonecessrio.Oqueprecisamosumaformadedeclararumponteirocomopldsema
necessidadedapalavrachavetypedef.Istopodeserfeito,e
int (*p1d)[10];
adeclaraocorreta,isto,pldaquiumponteiroparaumarrayde10inteirosdamesmaformaque
eleseriasefossedeclaradousandootipoArray.Notequeistodiferentede
int *p1d[10];
quefariaquepldfosseonomedeumarrayde10ponteirosparaotipoint.
9.PonteiroseAlocaoDinmicadeMemria
Existemvezesemqueconvenientealocarmemriaduranteaexecuodoprogramausandomalloc(),
calloc(),ououtrasfunesdealocao.Usarestaabordagempermiteprotelaradecisosobreo
tamanhodoblocodememrianecessrioparaarmazenarumarray,porexemplo,paraomomentode
execuodoprograma.Oupermiteusarumaseodamemriaparaarmazenarumarraydeinteirosem
certomomentonotempo,equandoaquelamemrianomaisnecessria,elapodeserliberadapara
outrosusos,comooarmazenamentodeumarraydeestruturas.
Quandoamemriaalocada,afunodealocao(comomalloc(),calloc(),etc.)retornaumponteiro.
Otipodesteponteirodependedotipodocompiladorusado,seumvelhocompiladorK&Rouum
compiladorANSInovo.Comocompiladorantigootipodoponteiroretornadochar,como
compiladorANSIvoid.
Sevocestusandoumcompiladormaisantigo,equeralocarmemriaparaumarraydeinteiros,voc
terquefazerumcastdoponteirocharretornadoparaumponteirointeiro.Porexemplo,paraalocal
espaopara10inteiros,poderamosescrever:
inf *iptr;
iptr = (int *)malloc(10 * sizeof(int));
if (iptr == NULL)

{ ... Rotina de erro vem aqui ... }
SevocestusandoumcompiladorANSI,malloc()retornaumponteirovoidecomoumponteirovoid
podeseratribudoaumavarivelponteirodequalquertipo,ocast(int*)mostradoacimano
necessrio.Adimensodoarraypodeserdeterminadaduranteaexecuoenonecessriadurantea
compilao.Ouseja,o10acimapoderiaserumavarivellidadeumarquivodedadosouteclado,ou
calculadabaseadaemalgumanecessidade,duranteaexecuo.
Devidoequivalnciaentreanotaodearrayeponteiros,umavezqueiptrtenhasidocriadocomo
mostradoacima,podeseusaranotaodearray.Porexemplo,podeseescrever:
int k;
for (k = 0; k < 10; k++)
iptr[k] = 2;
paracolocaremtodososelementosovalor2.
Mesmocomumentendimentorazoavelmentebomdeponteirosearrays,seexisteumlugaremqueo
novatoemCprovavelmenteirtropearnaprimeiravezquetrabalhar,aalocaodinmicadearrays
multidimensionais.Emgeral,gostaramosdepoderacessarelementosdestesarraysusandonotaode
array,enonotaodeponteiro,semprequepossvel.Dependendodaaplicaopodemosouno
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 24/39
conhecerasduasdimensesduranteacompilao.Istonoslevaavriasformasdeexecutaratarefa.
Comojvimos,quandoalocandodinamicamenteumarraydeumadimenso,suadimensopodeser
determinadaduranteaexecuo.Agora,quandousandoalocaodinmicadearraysdeordemmaior,
nsnoprecisamossaberaprimeiradimensoduranteacompilao.Seprecisamosounoconheceras
dimensesmaioresdependedecomoiremosescreverocdigo.Aquieuireidiscutirvriosmtodos
paraalocardinamicamenteespaoparaarraysbidimensionaisdeinteiros.
Primeiro,iremosconsiderarcasosemqueasegundadimensoconhecidaduranteacompilao.
Mtodo1
Umaformadelidarcomoproblemaatravsdousodapalavrachavetypedef.Paraalocarumarray
bidimensionaldeinteiros,lembrequeasduasnotaesseguintesresultamnageraodomesmocdigo
objeto:
multi[row][col] = 1; *(*(multi + row) + col) = 1;
Tambmverdadequeasduasnotaesaseguirgeramomesmocdigo:
multi[row] *(multi + row)
Comoodadireitadeveresultaremumponteiro,anotaodearraynaesquerdatambmdeveresultar
emumponteiro.Defato,multi[0]irretornarumponteiroparaoprimeirointeironaprimeiralinha,
multi[1]umponteiroparaoprimeirointeironasegundalinha,etc.Naverdade,multi[n]retornaum
ponteiroparaonsimoarraydestearraydearrays.Aquiapalavraponteiroestsendousadapara
representarumvalordeendereo.Apesardesteusosercomumnaliteratura,quandoestiverlendoeste
tipodedeclaraodevesesercuidadosparadistinguirentreoendereoconstantedeumarrayeuma
varivelponteiroqueumobjetodedadosemsi.
Considereagora:
Programa9.1
/* Program 9.1 from PTRTUT10.HTM 6/13/97 */

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

#define COLS 5

typedef int RowArray[COLS];
RowArray *rptr;

int main(void)
{
int nrows = 10;
int row, col;
rptr = malloc(nrows * COLS * sizeof(int));
for (row = 0; row < nrows; row++)
{
for (col = 0; col < COLS; col++)
{
rptr[row][col] = 17;
}
}

return 0;
}
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 25/39
NesteexemploeuassumiqueseestavausandoumcompiladorANSI,assimumcastnoponteirovoid
retornadopormalloc()nonecessrio.SevocestiverusandoumcompiladorK&Rantigovocter
defazerocastusando:
rptr = (RowArray *)malloc(... etc.
Usandoestaabordagem,rptrtemtodasascaractersticasdeumnomedearray(excetoquerptr
modificvel),eanotaodearraypodeserusadapelorestodoprograma.Istotambmsignificaquese
vocpretendeescreverumafunoparamodificarocontedodoarray,deveusarCOLScomoparte
dosparmetrosformaisdafuno,comonsfizemosquandodiscutimosapassagemdearrays
bidimensionaisparaumafuno.
Mtodo2
NoMtodo1acima,rptracabousendoumponteiroparaotipo"umarraydeumadimensodeCOLS
inteiros".Acontecequeexisteumasintaxequepodeserusadaparaestetiposemanecessidadedo
typedef.Seescrevermos:
int (*xptr)[COLS];
avarivelxptrtertodasasmesmascaractersticasdavarivelrptrnoMtodo1acima,eno
precisamosusarapalavrachavetypedef.Aqui,xptrumponteiroparaumarraydeinteiroseo
tamanhodoarraydadopelo#define COLS.Acolocaodosparntesistornaanotaodeponteiros
predominante,mesmoqueanotaodearraytenhaumamaiorprecedncia.Isto,setivssemosescrito
int *xptr[COLS];
teramosdefinidoxptrcomoumarraydeponteirosmantendoumnmerodeponteirosigualaodefinido
porCOLS.Noamesmacoisa,deformanenhuma.Entretanto,arraysdeponteirostemseuusona
alocaodinmicadearraysbidimensionais,comoveremosnosdoismtodosaseguir.
Mtodo3
Considereocasoondenoconhecemosonmerodeelementosdecadalinhaduranteacompilao,isto
,tantoonmerodelinhaseonmerodecolunasdevemserdeterminadosduranteaexecuo.Uma
formadefazeristoseriacriarumarraydeponteirosdotipointeentoalocarespaoparacadalinhae
apontarcadaumdestesponteirosacadaumadestaslinhas.Considereoexemplo:
Programa9.2
/* Program 9.2 from PTRTUT10.HTM 6/13/97 */

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

int main(void)
{
int nrows = 5; /* Both nrows and ncols could be evaluated */
int ncols = 10; /* or read in at run time */
int row;
int **rowptr;
rowptr = malloc(nrows * sizeof(int *));
if (rowptr == NULL)
{
puts("\nFailure to allocate room for row pointers.\n");
exit(0);
}
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 26/39

printf("\n\n\nIndex Pointer(hex) Pointer(dec) Diff.(dec)");

for (row = 0; row < nrows; row++)
{
rowptr[row] = malloc(ncols * sizeof(int));
if (rowptr[row] == NULL)
{
printf("\nFailure to allocate for row[%d]\n",row);
exit(0);
}
printf("\n%d %p %d", row, rowptr[row],
rowptr[row]);
if (row > 0)
printf(" %d",(int)(rowptr[row] - rowptr[row-1]));
}

return 0;
}
Nocdigoacima,rowptrumponteiroaumponteirodotipoint.Nestecasoeleapontaparao
primeiroelementodeumarraydeponteirosparaotipoint.Considereonmerodechamadasa
malloc():
Para obter espao para o array de ponteiros 1 chamada
Para obter espao para as linhas 5 chamadas
-----
Total 6 chamadas
Sevocescolherusarestaabordagem,notequemesmoquevocpossausaranotaodearraypara
acessarelementosindividuaisdoarray,comoporexemplo,rowptr[row][col] = 17;,istono
significaqueosdadosno"arraybidimensional"estejamcontguosnamemria.
Voc~epode,entretanto,usarnotaodearraycomoseelefosseumblococontnuodememria.Por
exemplo,vocpodeescrever:
rowptr[row][col] = 176;
exatametnecomoserowptrfosseonomedeumarraybidimensionalcriadoduranteacompilao.
Obviamenterowecoldevemestarnoslimitesdoarrayquefoicriado,exatamentecomoemumarray
criadoduranteacompilao.
Sevocquerterumblococontguodememriadedicadoaoarmazenamentodeelementosnoarray
vocpodefazercomonoexemploabaixo:
Mtodo4
Nestemtodonsalocamosumblocodememriaparaguardaroarrayinteiroprimeiro.Entocriamos
umarraydeponteirosparaapontarparacadalinha.Assim,mesmoqueoarraydeponteirossejausado,
oarrayemsiestcontguonamemria.Ocdigocomosegue:
Programa9.3
/* Program 9.3 from PTRTUT10.HTM 6/13/97 */

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

int main(void)
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 27/39
{
int **rptr;
int *aptr;
int *testptr;
int k;
int nrows = 5; /* Both nrows and ncols could be evaluated */
int ncols = 8; /* or read in at run time */
int row, col;

/* we now allocate the memory for the array */

aptr = malloc(nrows * ncols * sizeof(int));
if (aptr == NULL)
{
puts("\nFailure to allocate room for the array");
exit(0);
}

/* next we allocate room for the pointers to the rows */

rptr = malloc(nrows * sizeof(int *));
if (rptr == NULL)
{
puts("\nFailure to allocate room for pointers");
exit(0);
}

/* and now we 'point' the pointers */

for (k = 0; k < nrows; k++)
{
rptr[k] = aptr + (k * ncols);
}

/* Now we illustrate how the row pointers are incremented */
printf("\n\nIllustrating how row pointers are incremented");
printf("\n\nIndex Pointer(hex) Diff.(dec)");

for (row = 0; row < nrows; row++)
{
printf("\n%d %p", row, rptr[row]);
if (row > 0)
printf(" %d",(rptr[row] - rptr[row-1]));
}
printf("\n\nAnd now we print out the array\n");
for (row = 0; row < nrows; row++)
{
for (col = 0; col < ncols; col++)
{
rptr[row][col] = row + col;
printf("%d ", rptr[row][col]);
}
putchar('\n');
}

puts("\n");

/* and here we illustrate that we are, in fact, dealing with
a 2 dimensional array in a contiguous block of memory. */
printf("And now we demonstrate that they are contiguous in memory\n");

testptr = aptr;
for (row = 0; row < nrows; row++)
{
for (col = 0; col < ncols; col++)
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 28/39
{
printf("%d ", *(testptr++));
}
putchar('\n');
}

return 0;
}
Considere,novamente,onmerodechamadasamalloc()
Para obter espao para o array de ponteiros 1 chamada
Para obter espao para o array de ptrs 1 chamada
-----
Total 2 chamadas
Agora,cadachamadaamalloc()criaumoverheadadicionaldeespaojquemalloc()geralmente
implementadopelosistemaoperacionalformandoumalistaligadaquecontmdadossobreotamanho
dobloco.Mas,maisimportante,comgrandesarrays(vriascentenasdelinhas)manterocontroledo
queprecisaserliberadoquandochegaahorapodeserproblemtico.Isto,combinadocoma
contiguidadedoblocodedadosquepermiteainicializaodetudoparazerousandoomemset(),
parecequetornaasegundaalternativaapreferida.
Comoumexemplofinaldearraysmultidimensionaisiremosilustraraalocaodinmicadeumarrayde
trsdimenses.Esteexemploirilustrarumacoisamaisaserverificadaquandosefazestetipode
alocao.Porrazescitadasacima,iremosutilizaraabordagemapresentadanasegundaalternativa.
Considereoseguintecdigo:
Programa9.4
/* Program 9.4 from PTRTUT10.HTM 6/13/97 */

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

int X_DIM=16;
int Y_DIM=5;
int Z_DIM=3;

int main(void)
{
char *space;
char ***Arr3D;
int y, z;
ptrdiff_t diff;

/* first we set aside space for the array itself */

space = malloc(X_DIM * Y_DIM * Z_DIM * sizeof(char));

/* next we allocate space of an array of pointers, each
to eventually point to the first element of a
2 dimensional array of pointers to pointers */

Arr3D = malloc(Z_DIM * sizeof(char **));

/* and for each of these we assign a pointer to a newly
allocated array of pointers to a row */

for (z = 0; z < Z_DIM; z++)
{
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 29/39
Arr3D[z] = malloc(Y_DIM * sizeof(char *));

/* and for each space in this array we put a pointer to
the first element of each row in the array space
originally allocated */

for (y = 0; y < Y_DIM; y++)
{
Arr3D[z][y] = space + (z*(X_DIM * Y_DIM) + y*X_DIM);
}
}

/* And, now we check each address in our 3D array to see if
the indexing of the Arr3d pointer leads through in a
continuous manner */

for (z = 0; z < Z_DIM; z++)
{
printf("Location of array %d is %p\n", z, *Arr3D[z]);
for ( y = 0; y < Y_DIM; y++)
{
printf(" Array %d and Row %d starts at %p", z, y, Arr3D[z][y]);
diff = Arr3D[z][y] - space;
printf(" diff = %d ",diff);
printf(" z = %d y = %d\n", z, y);
}
}
return 0;
}
Sevocseguiuestetutorialatesteponto,nodeveterproblemasdecifrandoocdigoacimacombase
apenasnoscomentrios.Halgunspontosqueeugostariadedestacar.Comecemoscomalinhaque
tem:
Arr3D[z][y] = space + (z*(X_DIM * Y_DIM) + y*X_DIM);
Notequeaquispaceumponteiroparacaracter,quetemomesmotipodeArr3D[z][y].importante
quequandoseestsomandouminteiro,comooresultantedaexpresso(z*(X_DIM*Y_DIM)+
y*X_DIM)aumponteiro,oresultadoumnovovalordeponteiro.Equandoseestatribuindovaloers
deponteiroavariveisdeponteiroostiposdosdadosdovaloredavariveldevemcombinar.
10.PonteirosParaFunes
Atagoradiscutimosponteirosparaobjetosdedados.Ctambmpermiteadeclaraodeponteirospara
funes.Ponteirosparafunestemumavariedadedeusosealgunsdelesserodiscutidosaqui.
Considereoseguinteproblemareal.Vocquerescreverumafunoquecapazdeordenar
virtualmentequalquercoleodedadosquepodemserarmazenadosemumarray.Estepodeserum
arraydestrings,ouinteiros,oufloats,oumesmoestruturas.Oalgoritmodeordenamentopodesero
mesmoparatodos.Porexemplo,elepodeserumsimplesalgoritmobubblesort,ouoalgoritmomais
complexoshellsortouquicksort.Iremosutilizarumsimplesbubblesortparanossademonstrao.
Sedgewick[1]descreveuobubblesortusandocdigoCconfigurandoumafunoquequandorecebe
umponteiroparaumarrayirordenaromesmo.Sechamarmosestafunobubble(),umprogramade
ordenamentodescritoporbubble_1.c,quesegue:
Programabubble_1.c
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 30/39
/*-------------------- bubble_1.c --------------------*/

/* Program bubble_1.c from PTRTUT10.HTM 6/13/97 */

#include <stdio.h>

int arr[10] = { 3,6,1,2,3,8,4,1,7,2};

void bubble(int a[], int N);

int main(void)
{
int i;
putchar('\n');
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
bubble(arr,10);
putchar('\n');

for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}

void bubble(int a[], int N)
{
int i, j, t;
for (i = N-1; i >= 0; i--)
{
for (j = 1; j <= i; j++)
{
if (a[j-1] > a[j])
{
t = a[j-1];
a[j-1] = a[j];
a[j] = t;
}
}
}
}

/*---------------------- end bubble_1.c -----------------------*/
Obubblesortumdosordenamentosmaissimples.Oalgoritmoexaminaoarraydosegundoato
ltimoelemento,comparandocadaelementocomoqueoprecede.Seumdoselementosqueprecede
maiorqueoelementoatual,osdoissotrocadosdeformaqueomaiorvaificandoprximodofimdo
array.Noprimeiropasso,istoresultanomaiorelementoindoparaofimdoarray.Oarrayagora
limitadoatodososelementosexcetooltimoeoprocessorepetido.Istocolocaoprximomaior
elementonaposioanteriordomaiorelemento.Oprocessorepetidoporumnmerodevezesigual
aonmerodeelementosmenos1.Oresultadofinalumarrayordenado.
Aquinossasfunesforamfeitasparaordenarumarraydeinteiros.Assim,nalinha1estamos
comparandointeirosenaslinhas2a4estamosusandouminteirotemporrioparaguardarinteiros.O
quequeremosfazeragoraversepodemosconverterestecdigodeformaquepossamosusarqualquer
tipodedado,isto,noficarmosrestritosainteiros.
Aomesmotemponoqueremosterqueanalisarnossoalgoritmoeocdigoassociadocomeletodavez
queusarmosomesmo.Comeamosremovendoacomparaodedentrodafunobubble()deformaa
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 31/39
tornarrelativamentefcilmodificarafunodecomparaosemterquereescreverporesrelacionadas
aoalgoritmoemsim.Oresultadoestembubble_2.c:
Programabubble_2.c
/*---------------------- bubble_2.c -------------------------*/

/* Program bubble_2.c from PTRTUT10.HTM 6/13/97 */

/* Separating the comparison function */

#include <stdio.h>

int arr[10] = { 3,6,1,2,3,8,4,1,7,2};

void bubble(int a[], int N);
int compare(int m, int n);

int main(void)
{
int i;
putchar('\n');
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
bubble(arr,10);
putchar('\n');

for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}

void bubble(int a[], int N)

{
int i, j, t;
for (i = N-1; i >= 0; i--)
{
for (j = 1; j <= i; j++)
{
if (compare(a[j-1], a[j]))
{
t = a[j-1];
a[j-1] = a[j];
a[j] = t;
}
}
}
}

int compare(int m, int n)
{
return (m > n);
}
/*--------------------- end of bubble_2.c -----------------------*/
Senossoobjetivofazernossarotinadeordenamentoindependentedotipodedados,umaformade
fazeristousarponteirosparaotipovoidparaapontarparaosdadosemvezdeusarotipointeiro.
Comopartidanestadireo,vamosmodificaralgumascoisasnoprogramaacimadeformaqueponteiros
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 32/39
possamserutilizados.Paracomear,vamosficarcomponteirosparaotipointeiro.
Programabubble_3.c
/*----------------------- bubble_3.c -------------------------*/

/* Program bubble_3.c from PTRTUT10.HTM 6/13/97 */

#include <stdio.h>

int arr[10] = { 3,6,1,2,3,8,4,1,7,2};

void bubble(int *p, int N);
int compare(int *m, int *n);

int main(void)
{
int i;
putchar('\n');

for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
bubble(arr,10);
putchar('\n');

for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}

void bubble(int *p, int N)
{
int i, j, t;
for (i = N-1; i >= 0; i--)
{
for (j = 1; j <= i; j++)
{
if (compare(&p[j-1], &p[j]))
{
t = p[j-1];
p[j-1] = p[j];
p[j] = t;
}
}
}
}

int compare(int *m, int *n)
{
return (*m > *n);
}

/*------------------ end of bubble3.c -------------------------*/
Noteasalteraes.Estamosagorapassandoumponteiroparauminteiro(ouarraydeinteiros)para
bubble().Ededentrodebubbleestamospassandoponteirosparaoselementosdoarrayquequeremos
compararparaanossafunodecomparao.E,obviamente,estamosdereferenciandoestesponteiros
emnossafunocompare()parafazeracomparaoemsi.Nossoprximopassoserconverteros
ponteirosembubble()paraponteirosdotipovoiddeformaqueafunofiquemaisinsensvelaotipo.
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 33/39
Istoestmostradonobubble_4.
Programabubble_4.c
/*------------------ bubble_4.c ----------------------------*/

/* Program bubble_4.c from PTRTUT10,HTM 6/13/97 */

#include <stdio.h>

int arr[10] = { 3,6,1,2,3,8,4,1,7,2};

void bubble(int *p, int N);
int compare(void *m, void *n);

int main(void)
{
int i;
putchar('\n');

for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
bubble(arr,10);
putchar('\n');

for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}

void bubble(int *p, int N)
{
int i, j, t;
for (i = N-1; i >= 0; i--)
{
for (j = 1; j <= i; j++)
{
if (compare((void *)&p[j-1], (void *)&p[j]))
{
t = p[j-1];
p[j-1] = p[j];
p[j] = t;
}
}
}
}

int compare(void *m, void *n)
{
int *m1, *n1;
m1 = (int *)m;
n1 = (int *)n;
return (*m1 > *n1);
}

/*------------------ end of bubble_4.c ---------------------*/
Noteque,aofazeristo,emcompare()temosqueintroduzirocastingdoponteirotipovoidparaotipo
realsendoordenado.Mas,comoveremosmaistarde,istonoproblema.Ecomooqueestsendo
passadoparabubble()aindaumponteiroparaumarraydeinteiros,temosquefazerocastdestes
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 34/39
ponteirosparaponteirosparainteirosquandopassamososmesmoscomoparmetrosemnossachamada
acompare().
Agoravamostratardoprolemadoquepassamosparabubble().Queremosqueoprimeiroparmetro
paraaquelafunosejatambmumponteiroparavoid.Mas,istosignificaquedentrodebubble()
precisamosfazeralgosoberavarivelt,queatualmenteuminteiro.Almdisso,ondeusamost =
p[j-1];otipodep[j-1]precisaserconhecidoparasaberquantosbytescopiarparaavarivelt(ouo
quequerquecoloquemosnolugardet).
Atualmente,nobubble_4.c,oconhecimentodentrodebubble()sobreotipododadosendoordenado
(e,portanto,otamanhodecadaelementoindividual)obtidodofatoqueoprimeiroparmetroum
ponteiroparaotipointeiro.Sequeremosquebubble()ordentequalquertipodedado,precisamosfazer
queaqueleponteiroaponteparaotipovoid.Mas,aofazeristo,iremosperderainformaosobreo
tamanhodoselementosindividuaisdentrodoarray.Assim,embubble_5.c,iremosacrescentarum
parmetroseparadoparatratarestainformaodetamanho.
Estasalteraes,debubble_4.cparabubble_5.cso,talvez,umpoucomaisextensivasqueasque
fizemosnosexemplosanteriores.Assim,comparecuidadosamenteosdoismdulosparaveras
diferenas.
Programabubble_5.c
/*---------------------- bubble5.c ---------------------------*/

/* Program bubble_5.c from PTRTUT10.HTM 6/13/97 */



#include <stdio.h>
#include <string.h>

long arr[10] = { 3,6,1,2,3,8,4,1,7,2};

void bubble(void *p, size_t width, int N);
int compare(void *m, void *n);

int main(void)
{
int i;
putchar('\n');

for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
bubble(arr, sizeof(long), 10);
putchar('\n');

for (i = 0; i < 10; i++)
{
printf("%ld ", arr[i]);
}

return 0;
}

void bubble(void *p, size_t width, int N)
{
int i, j;
unsigned char buf[4];
unsigned char *bp = p;
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 35/39

for (i = N-1; i >= 0; i--)
{
for (j = 1; j <= i; j++)
{
if (compare((void *)(bp + width*(j-1)),
(void *)(bp + j*width))) /* 1 */
{
/* t = p[j-1]; */
memcpy(buf, bp + width*(j-1), width);
/* p[j-1] = p[j]; */
memcpy(bp + width*(j-1), bp + j*width , width);
/* p[j] = t; */
memcpy(bp + j*width, buf, width);
}
}
}
}

int compare(void *m, void *n)
{
long *m1, *n1;
m1 = (long *)m;
n1 = (long *)n;
return (*m1 > *n1);
}

/*--------------------- end of bubble5.c ---------------------*/
Notequeeumudeiotipodosdadosdoarraydeintparalongparailustrarasmudanasnecessriasna
funocompare().Dentrodebubble()eumedescarteidavarivelt(queteramosdetermudadodo
tipointparaotipolong).Euacrescenteiumbufferdetamanho4deunsignedchar,queotamanho
necessrioparaarmazenarumlong(istosernovamentealteradoemfuturasmodificaesaeste
cdigo).Oponteirounsignedchar*bpusadoparaapontarparaabasedoarrayaserordenado,isto,
oprimeiroelementodaquelearray.
Temostambmquemodificaroquepassadoacompare(),ecomofaremosatrocadoselementosque
acomparaoindicaprecisaremsertrocados.Ousodememcpy()eanotaodeponteirosemvezda
notaodearrayajudanareduodasensibilidadeaotipo.
Novamente,fazerumacomparaocuidadosadebubble_5.ccombubble_4.cpoderesultaremum
entendimentomaiorsobreoqueestacontecendoeporqu.
Agoravamosparabubble_6.v,ondeiremosusaramesmafunobubble()queusamosembubble_5
paraordenarstringsemvezdeinteiroslongos.Obviamentetemosquealterarafunodecomparaoj
queaformaquestringssocomparadasdiferentedaformaqueinteiroslongossocomparados.Eem
bubble_6.cnsexclumosaslinhasdebubble()queestavamcomentadasembubble_5.c
Programabubble_6.c
/*--------------------- bubble6.c ---------------------*/
/* Program bubble_6.c from PTRTUT10.HTM 6/13/97 */

#include <stdio.h>
#include <string.h>

#define MAX_BUF 256

char arr2[5][20] = { "Mickey Mouse",

"Donald Duck",
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 36/39

"Minnie Mouse",

"Goofy",

"Ted Jensen" };

void bubble(void *p, int width, int N);
int compare(void *m, void *n);

int main(void)
{
int i;
putchar('\n');

for (i = 0; i < 5; i++)
{
printf("%s\n", arr2[i]);
}
bubble(arr2, 20, 5);
putchar('\n\n');

for (i = 0; i < 5; i++)
{
printf("%s\n", arr2[i]);
}
return 0;
}

void bubble(void *p, int width, int N)
{
int i, j, k;
unsigned char buf[MAX_BUF];
unsigned char *bp = p;

for (i = N-1; i >= 0; i--)
{
for (j = 1; j <= i; j++)
{
k = compare((void *)(bp + width*(j-1)), (void *)(bp + j*width));
if (k > 0)
{
memcpy(buf, bp + width*(j-1), width);
memcpy(bp + width*(j-1), bp + j*width , width);
memcpy(bp + j*width, buf, width);
}
}
}
}

int compare(void *m, void *n)
{
char *m1 = m;
char *n1 = n;
return (strcmp(m1,n1));
}

/*------------------- end of bubble6.c ---------------------*/
Mas,ofatoquebubble()tenhaficadoinalteradodaquiloquefoiusadoembubble_5.cindicaqeua
funocapazdeordenarumagrandevariedadedetiposdedados.Oquefaltafazerpassarpara
bubble()onomedafunodecomparaoquequeremosutilizar,deformaqueafunosejarealmente
universal.Damesmaformaqueumarrayoendereodoprimeiroelementodoarraynosegmentode
dados,onomedeumafunotraduzseparaoendereodaquelafunonosegmentodecdigo.Assim,
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 37/39
precisamosusarumponteiroparaumafuno.Nestecaso,afunodecomparao.
Ponteirosparafunesdevemcombinarcomasfunesapontadasnonmeroetipodosparmetroseo
tipodovalorderetorno.Emnossocaso,declaramosnossoponteiroparafunocomo:
int (*fptr)(const void *p1, const void *p2);
Noetquesetivssemosescrito:
int *fptr(const void *p1, const void *p2);
teramosfeitooprottipoparaumafunoqueretornaumponteirodotipoint.IstoporqueemCo
operadorparntesis()temumaprecednciamaiorqueooperador*ponteiro.Colocandooparntesis
emtornodastring(*fptr)nsindicamosqueestamosdeclarandoumponteiroparaumafuno.
Aboransmodificamosnossadeclaraodebubble()peloacrscimo,comoseuquartoparmetro,um
ponteirodefunodotipoapropriado.assimqueoprottipodafunofica:
void bubble(void *p, int width, int N,
int(*fptr)(const void *, const void *));
Quandochamarmosbubble(),nsinserimosonomedafunodecomparaoquequeremosutilizar.O
programabubble_7.cilustracomoestaabordagempermiteousodamesmafunobubble()para
ordenardiferentestiposdedados.
Programabubble_7.c
/*------------------- bubble7.c ------------------*/

/* Program bubble_7.c from PTRTUT10.HTM 6/10/97 */

#include <stdio.h>
#include <string.h>

#define MAX_BUF 256

long arr[10] = { 3,6,1,2,3,8,4,1,7,2};
char arr2[5][20] = { "Mickey Mouse",
"Donald Duck",
"Minnie Mouse",
"Goofy",
"Ted Jensen" };

void bubble(void *p, int width, int N,
int(*fptr)(const void *, const void *));
int compare_string(const void *m, const void *n);
int compare_long(const void *m, const void *n);

int main(void)
{
int i;
puts("\nBefore Sorting:\n");

for (i = 0; i < 10; i++) /* show the long ints */
{
printf("%ld ",arr[i]);
}
puts("\n");

for (i = 0; i < 5; i++) /* show the strings */
{
printf("%s\n", arr2[i]);
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 38/39
}
bubble(arr, 4, 10, compare_long); /* sort the longs */
bubble(arr2, 20, 5, compare_string); /* sort the strings */
puts("\n\nAfter Sorting:\n");

for (i = 0; i < 10; i++) /* show the sorted longs */
{
printf("%d ",arr[i]);
}
puts("\n");

for (i = 0; i < 5; i++) /* show the sorted strings */
{
printf("%s\n", arr2[i]);
}
return 0;
}

void bubble(void *p, int width, int N,
int(*fptr)(const void *, const void *))
{
int i, j, k;
unsigned char buf[MAX_BUF];
unsigned char *bp = p;

for (i = N-1; i >= 0; i--)
{
for (j = 1; j <= i; j++)
{
k = fptr((void *)(bp + width*(j-1)), (void *)(bp + j*width));
if (k > 0)
{
memcpy(buf, bp + width*(j-1), width);
memcpy(bp + width*(j-1), bp + j*width , width);
memcpy(bp + j*width, buf, width);
}
}
}
}

int compare_string(const void *m, const void *n)
{
char *m1 = (char *)m;
char *n1 = (char *)n;
return (strcmp(m1,n1));
}

int compare_long(const void *m, const void *n)
{
long *m1, *n1;
m1 = (long *)m;
n1 = (long *)n;
return (*m1 > *n1);
}

/*----------------- end of bubble7.c -----------------*/
Referncias
[1]"AlgorithmsinC"
RobertSedgewick
AddisonWesley
3/7/2014 Tutorial de Ponteiros e Arrays em C
http://cesarakg.freeshell.org/pointers.html 39/39
ISBN0201514257
Eplogo
Euescreviomaterialqueoleitortememmosagoraparadarumaintroduoaponteirosparanovatos
noC.EmC,quantomaisseentendesobreponteiros,maioraflexibilidadequesetemnocdigoescrito.
Otextoacimafoiexpandidodomeuprimeirotrabalhonestetpicoquerecebeuonomedeptr_help.txt
eeraencontradonasprimeirasversesdacoleodecdigoCSNIPPETSdeBobStout.Ocontedo
nestaversofoiatualizadoapartirdocdigoemPTRTUTOT.ZIPincludoemSNIP9510.ZIP.
Euestousempreprontoaaceitarcrticasconstrutivassobreestematerial,ousolicitaesderevisopara
aadiodeoutromaterialrelevante.Assimsendo,sevoctiverquestes,comentrios,crticas,etc.
sobreestaapresentao,euapreciariaimensamenteseucontatoviaemailparaminhacontaem
tjensen@ix.netcom.com.

Вам также может понравиться