Buscar

Alocação Dinâmica de Memória em C++

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 9 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 9 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 9 páginas

Prévia do material em texto

Plano	de	Aula:	Alocação	Dinâmica	de	Memória	(Parte	I)
ESTRUTURA	DE	DADOS	-	CCT0637
Título
Alocação	Dinâmica	de	Memória	(Parte	I)
Número	de	Aulas	por	Semana
Número	de	Semana	de	Aula
4
Tema
Alocação	Dinâmica	de	Memória	(Parte	I)
Objetivos
Possibilitar	ao	aluno:
-	Reconhecer	os	conceitos	fundamentais	relacionados	à	Alocação	Dinâmica	de
Memória
-	Analisar	como	acontece	a	Alocação	Dinâmica	de	Memória	em	C++
-	Aplicar	o	tipo	de	dado	Ponteiro	e	os	seus	operadores	associados:	endereço,
indireção,	seta	no	desenvolvimento	de	algoritmos
-	Desenvolver,	no	laboratório	de	informática,	os	conceitos	sobre	Ponteiros	e
suas	operações	associadas	por	meio	de	exercícios	guiados
Estrutura	do	Conteúdo
CONTEÚDOS:
Alocação	Dinâmica	de	Memória
Fundamentos
Aplicação	em	C++:	Ponteiros
Operador	de	endereço	(&),	operador	de	indireção	(*)	e	operador
seta	(->)
RESUMO	DE	CONCEITOS:
Definições
Ponteiros	são	fundamentais	para	a	programação	bem	sucedida	em	C++:
Passagem	de	parâmetros	por	referência;
Alocação	dinâmica	de	memória;
Aumentar	a	eficiência	de	certar	rotinas.
Essencialmente,	 um	ponteiro	 nada	mais	 é	 do	 que	 uma	variável	 que	 ao
invés	de	conter	um	valor,	contém	um	endereço	de	memória.
O	conceito	de	utilizar	espaço	em	memória	não	é	em	absoluto	novo.	De
fato,	linguagens	de	máquina	utilizam	tal	conceito	todo	o	tempo.
Exemplo	1	-	mnemônico	(Intel	80C51)	que	executa	a	soma	do	conteúdo
da	RAM	interna	apontada	por	Ri	ao	Acumulador:
ADD	A,	@RI
Declaração	de	Ponteiros
<tipo>	*<nome_variavel>
Exemplo	2	-	exemplo	da	declaração	de	diversos	ponteiros:
int	*iptr;
float	*fptr;
char	*cptr;
Como	um	ponteiro	 armazena	um	endereço	 de	memória	 e	 não	 um	valor
específico,	pode	parecer	estranho	a	primeira	vista	que	seja	requerida	a
associação	de	um	 tipo	ao	se	declaram	um	ponteiro.	No	entanto,	muito
comumente,	 deseja-se	 acessar	 o	 valor	 armazenado	 pela	 variável
apontada	por	 um	ponteiro.	Desta	 forma,	 o	 tipo	do	ponteiro	 serve	para
instruir	 o	 compilador	 na	 maneira	 pela	 qual	 o	 dado	 pontado	 será
acessado.	 Essencialmente,	 o	 tipo	 de	 dados	 e	 a	 codificação	 do	 dado
(como	 os	 bits	 serão	 interpretados,	 necessário	 por	 exemplo	 para	 tipos
com	base	na	notação	de	ponto	flutuante).
Operadores	de	Ponteiros
"*"	conteúdo	/	 indireção:	aplicado	a	um	variável	tipo	ponteiro,	retorna	o
conteúdo	do	endereço	apontado	pelo	ponteiro;
"&"	 endereço:	 aplicado	 a	 uma	 variável,	 retorna	 seu	 endereço	 de
memória.
Exemplo	3	-	exemplo	da	utilização	de	ambos	os	operadores	unários:
int	count;
int	*iptr;
iptr	=	&count;
cout	<<	*iptr;
Operador	Seta
Para	 começar	 e	 deixar	mais	 claro	 definimos	 uma	 estrutura	 simples	 com	 dois
campos.
	struct	{
										int	i;	
										double	f;	
								}	minha_estrutura;
O	passo	seguinte	é	definir	um	ponteiro	para	essa	estrutura.
								struct	minha_estrutura	*p_minha_estrutura;
A	partir	do	ponteiro	podemos	ter	acesso	a	um	campo	da	estrutura	usando	um
seletor	"->"	(uma	flecha).
								p_minha_estrutura->	i	=	1;	
								p_minha_estrutura->	f	=	1.2;
O	mesmo	resultado	pode	ser	obtido	da	seguinte	forma.
								(*p_minha_estrutura).i	=	1;	
								(*p_minha_estrutura).f	=	1.2;
Inicialização	de	Ponteiros
Ponteiros	são	 inicializados	ao	definirmos	um	endereço	para	o	qual	eles
devem	apontar.
Ponteiros	 não	 inicializados	 são	 também	 chamados	 de	 "ponteiros
selvagens"
A	não	 inicialização	de	ponteiros	 é	um	dos	principais	 fatores	para	erros
em	tempo	de	execução	em	programas	escritos	na	 linguagem	C++.	Tais
erros	 são	 difíceis	 de	 identificar	 e	 corrigir,	 porque	 o	 tempo	 decorrido
entre	o	acesso	 ilegal	à	memória	de	um	ponteiro	e	a	efetiva	ocorrência
do	erro	é	imprevisível.
Uma	maneira	de	garantir	que	um	ponteiro	declarado	não	apontará	para
um	lugar	qualquer	da	memória	é	atribuir	o	valor	NULL	para	o	mesmo.
int	*iptr	=	null;
Ponteiros	e	Arrays
Ponteiros	 são	 muito	 utilizados	 para	 a	 navegação	 de	 arrays,
principalmente	 de	 arrays	 alocados	 de	 maneira	 dinâmica.	 A	 idéia
geral	é	alocar	o	array	usando	ou	o	método	estático	ou	o	dinâmico	e
então	 criar	 uma	 variável	 do	 tipo	 ponteiro	 que	 apontará	 para	 a
primeira	 posição	 do	 ponteiro.	 Utilizando	 aritmética	 de	 ponteiros
(incremento,	 decremento,	 saltos)	 é	 possível	 percorrer	 o	 array	 sem
ter	que	se	preocupar	com	quantos	bytes	devem	ser	acessados,	pois
a	tipagem	do	ponteiro	cuidará	deste	detalhe.
É	importante	ressaltar	que	a	utilização	de	ponteiros	para	indexação
de	arrays	apresenta	um	risco	intrínseco.
Aritmética	de	Ponteiros
Uma	das	grandes	vantagens	decorrentes	da	utilização	de	ponteiros
é	a	possibilidade	de	indexar	posições	de	memória	de	maneira	fácil	e
intuitiva.	 Tal	 endereçamento	 é	 alcançado	 a	 partir	 de	 operações
aritméticas	simples	que	tem	como	objetos	variáveis	do	tipo	ponteiro.
Operandos	unários:
++	incremento	unitário;
--	decremento	unitário.
Suponha	que	p	é	um	ponteiro	do	 tipo	 inteiro	e	suponha	que	o	 tipo
inteiro	 na	 arquitetura	 de	 destino	 do	 exemplo	 sejam	 representados
por	2	bytes	cada.	Considere	o	seguinte	trecho	de	código:
int	vet[10];
int	*iptr;
iptr	=	vet;
iptr++;
Exemplo	4	-	navegação	de	arrays	usando	ponteiros
Assumindo	 que	 o	 array	 "vet"	 seja	 alocado	 pelo	 "loader"	 do	 sistema
operacional	 iniciando	 na	 posição	 00H,	 iptr	 erá	 apontar	 para	 a	 posição
00H	 inicialmente.	 Ao	 se	 executar	 a	 operação	 iptr++,	 o	 endereço
apontado	 por	 iptr	 será	 incrementado	 em	 uma	 unidade,	 o	 que
corresponderá,	dado	o	fato	de	que	inteiros	são	representados	por	dois
bytes,	ao	endereço	02H.
Comparação	de	Ponteiros
O	 ponto	 importante	 a	 respeito	 da	 comparação	 de	 ponteiros	 a	 ser
considerado	 diz	 respeito	 a	 semântica	 da	 comparação.	 Como
ponteiros	 são	 variáveis	 que	 contém	 endereços	 de	 memória,	 ao
compararmos	 ponteiros	 o	 que	 estamos	 fazendo	 realmente	 é
verificando	se	dois	endereços	de	memória	são	idênticos	ou	não.
A	 primeira	 vista,	 tal	 tipo	 de	 comparação	 pode	 parecer	 de	 pouca
importância,	 no	 entanto	 ela	 será	 de	 grande	 valor	 futuramente
quando	 ponteiros	 forem	 utilizados	 para	 manipular	 estruturas	 de
dados	 complexas	 tal	 como	 listas	 ligadas	 ou	 árvores.	 Podemos
comparar	 se	 dois	 ponteiros	 são	 iguais	 menores	 ou	 maiores
exatamente	como	se	compararam	valores	de	variáveis.
int	vet[7];
int	*iptr1,	*iptr2;
iptr1	=	&vet[0];
iptr2	=	&vet[6];
iptr1	==	iptr2;
iptr1	<		iptr2;
iptr1	>		iptr2;
iptr1	<=	iptr2;
Exemplo	5	-	comparação	de	ponteiros
Programa	Exemplo
#include	<iostream>
#include	<stdlib.h>
using	namespace	std;
	
int	main()
{
				//int	count	=	22;
				//int	aux	=	456;
				int	*iptr	=	(int*)	malloc(100*sizeof(int));
				//int	*idx	=	NULL;
				//idx	=	iptr;
				int	i;
				for	(i	=	0;	i	<	100;	i++)
				{
								iptr[i]	=	i	*	10;
								//*idx	=	i	*	10;
								//idx++;
				}
	
				for	(i	=	0;	i	<	10;	i++)
				{
								cout	<<	"Elemento	"	<<	i	<<	"	=	"	<<	iptr[i]	<<	endl;
				}
	
				//iptr	=	&count;
				/*
				if	(iptr	!=	NULL)
				{
								cout	<<	"Endereco:	"	<<	&count	<<	"	-	Valor:	"	<<	count	<<
endl;
								cout	<<	"Ponteiro:	"	<<	iptr	<<	"	-	Valor0	"	<<	iptr[0]	<<	"	-
Valor1	"	<<		iptr[1]	<<	endl;
				}
				else
				{
								cout	<<	"Ponteiro	Nulo"	<<	endl;
				}
				*/
				return	0;
}
Alocação	de	vetores	de	Strings
#include	<iostream>
#include	<stdlib.h>
using	namespace	std;
	
#define	SIZE		2
	
int	main()
{
				int	i;
				//	Vetor	estatico	de	strings	estaticas
				char	vet1[SIZE][255]	=		{	"Estatico-1",	"Estatico-2"	};
				for	(i	=	0;	i	<	SIZE;	i++)
				{
																cout	<<	vet1[0]	<<	"	-	"	<<	vet1[1]	<<	endl;
				}
				//	Vetor	dinamico	de	strings	dinamicas
				char	**vet;
				vet	=	(char**)	new	char[SIZE];
				for	(i	=	0;	i	<	SIZE;	i++)
				{									
																vet[i]	=	new	char[255];//malloc	(255	*	sizeof(char));
																cout	<<	vet[i]	<<	"Dinamico-"	<<	i	<<	endl;
				}
				for	(i	=	0;	i	<	SIZE;	i++)
				{
																cout	<<	vet[i]	<<	endl;
				}
												
				return	0;
}
Aplicação	Prática	Teórica
SUGESTÃO	DE	EXERCÍCIOSPARA	SEMANA	04
	
TEÓRICOS
1.	 Ano:	 2010	 /	 Banca:	 FCC	 /	 Órgão:	 TRE-AM	 /	 Prova:	 Técnico	 Judiciário	 -
Programação	de	Sistemas
	
Na	linguagem	C++,	considere:
I.	O	endereço	armazenado	em	um	ponteiro	deve	ser	do	mesmo
tipo	 que	 o	 ponteiro	 (ex.	 um	 ponteiro	 para	 um	 int	 não	 pode
armazenar	o	endereço	de	um	float).
II.	Exceção	à	regra	apontada	em	(I)	é	o	ponteiro	void.
III.	Não	é	possível	 chamar	uma	 função	 segundo	 seu	endereço,
ainda	que	por	meio	de	um	ponteiro	que	armazena	o	endereço
de	início	dessa	função.
Está	correto	o	que	se	afirma	em
a)	I,	apenas.
b)	II,	apenas.
c)	I	e	II,	apenas.
d)	II	e	III,	apenas.
e)	I,	II	e	III.
	
1.	 Ano:	 2004	 /	 Banca:	 CESPE	 /	 Órgão:	 TRE-AL	 /	 Prova:	 Analista	 Judiciário	 -
Tecnologia	da	Informação
	
A	atividade	de	programação	 requer	conhecimento	 técnico	de	diversas
formas	de	algoritmos	e	estruturas	de	controle	e	de	dados.	Acerca	dos
elementos	 técnicos	 da	 atividade	 de	 programação,	 julgue	 os	 itens	 a
seguir.
	
Um	ponteiro	definido	como	um	dos	elementos	de	um	tipo	estruturado
de	 dados	 pode	 apontar	 para	 uma	 instância	 de	 dados	 desse	 mesmo
tipo.
(					)	Certo					(					)	Errado
	
1.	 Ano:	 2009	 /	 Banca:	 CESPE	 /	 Órgão:	 TRE-GO	 /	 Prova:	 Técnico	 Judiciário	 -
Programação	de	Sistemas
Considerando	as	definições	em	linguagem	C	mostradas	acima,	assinale
a	opção	correta.
a)	 A	 utilização	 de	 (char*)	 é	 um	 cast,	 que	 converte	 um	 tipo	 de
dados	em	outro.
b)	 As	 variáveis	 px	 e	 pc	 apontam	 para	 posições	 de	 memória
diferentes.
c)	 É	 correto	 afirmar	 que	 px	+	 1	 e	 (*pc)	+	 1	 apontam	 para	 as
mesmas	posições	de	memória.
d)	 Se	 px	 é	 um	 ponteiro	 para	 a	 variável	 x	 de	 tipo	 float,	 a
expressão	 px	 +	 1	 se	 refere	 ao	 byte	 seguinte	 na	 memória,	 a
partir	do	endereço	de	x.
	
1.	 Ano:	 2010	 /	 Banca:	 CESGRANRIO	 /	 Órgão:	 IBGE	 /	 Prova:	 Analista	 de
Sistemas
Para	os	recursos	presentes	na	linguagem	de	programação	C,	são	feitas
as	afirmativas	abaixo.
I	 -	 Permite	 acesso	 de	 baixo	 nível	 através	 da	 introdução	 de
código	Assembly	no	programa	C.
II	 -	 A	 passagem	 de	 parâmetros	 por	 referência	 para	 funções
pode	ser	simulada	através	da	utilização	de	ponteiros.
III	 -	 O	 tipo	 de	 dados	 typedef	 são	 estruturas	 variáveis	 que
permitem	 que	 dados	 relacionados	 sejam	 combinados	 e
manipulados	como	um	todo.
Está(ão)	correta(s)	a(s)	afirmativa(s)
a)	I,	apenas.
b)	II,	apenas.
c)	III,	apenas.
d)	I	e	II,	apenas.
e)	I,	II	e	III.
	
	
1.	 Ano:	2014	/	Banca:	UNIRIO	/	Órgão:	UNIRIO	/	Prova:	Analista	Tecnologia	da
Informação	-	Desenvolvimento	de	Sistemas
Sobre	as	funções,	é	CORRETO	afirmar	que
a)	na	passagem	por	valor,	o	parâmetro	que	vai	ser	passado	na
chamada	 da	 função	 deve	 ser	 uma	 variável,	 de	 tal	 forma	 que
uma	 alteração	 de	 valor	 neste	 parâmetro	 também	 altera	 a
variável	correspondente.
b)	 na	 passagem	 por	 referência,	 o	 parâmetro	 que	 vai	 ser
passado	 na	 chamada	 da	 função	 deve	 ser	 uma	 variável,	 de	 tal
forma	 que	 uma	 alteração	 de	 valor	 neste	 parâmetro	 também
altera	a	variável	correspondente.
c)	 uma	 variável	 é	 dita	 global	 quando	 a	 sua	 passagem	 no
momento	 da	 chamada	 de	 uma	 função	 se	 dá	 tanto	 por	 valor
quanto	 por	 referência,	 enquanto	 que	 uma	 variável	 é	 dita	 local
quando	esta	passagem	se	dá,	apenas,	por	valor.
d)	 na	 passagem	 por	 valor,	 o	 parâmetro	 passado	 na	 chamada
da	 função	 é	 o	 ponteiro	 para	 a	 variável	 que	 contém	 o	 valor
desejado.
	
1.	 Ano:	2008	/	Banca:	ESAF	/	Órgão:	Prefeitura	de	Natal	-	RN	/	Prova:	Auditor
do	Tesouro	Municipal	-	Tecnologia	da	Informação
	
Analise	 as	 seguintes	 afirmações	 relacionadas	 a	 conceitos	 básicos
sobre	Programação:
I.	 Um	 procedimento	 é	 um	 conjunto	 de	 comandos	 para	 uma
tarefa	 específica	 referenciada	 por	 um	 nome	 no	 algoritmo
principal,	 retornando	 um	 determinado	 valor	 no	 seu	 próprio
nome.
II.	Podem-se	 inserir	módulos	em	um	algoritmo.	Para	 isso,	pode-
se	 utilizar	 "Procedimentos"	 ou	 "Funções".	 As	 ações	 das
"Funções"	 e	 dos	 "Procedimentos"	 são	 hierarquicamente
subordinadas	a	um	módulo	principal.
III.	Cada	"Função"	ou	"Procedimento"	pode	utilizar	constantes	ou
variáveis	 do	 módulo	 principal	 ou	 definir	 suas	 próprias
constantes	ou	variáveis.
IV.	 Uma	 variável	 global	 indica	 o	 endereço	 onde	 um	 valor	 é
armazenado	na	memória	do	computador	enquanto	um	ponteiro
representa	um	valor	numérico	real.
Indique	a	opção	que	contenha	todas	as	afirmações	verdadeiras.
a)	I	e	II.
b)	II	e	III.
c)	III	e	IV.
d)	I	e	III.
e)	II	e	IV.
	
1.	 Ano:	 2006	 /	 Banca:	 ESAF	 /	 Órgão:	 CGU	 /	 Prova:	 Analista	 de	 Finanças	 e
Controle	-	Tecnologia	da	Informação
	
Analise	 as	 seguintes	 afirmações	 relacionadas	 a	 conceitos	 básicos	 de
Programação	de	Computadores.
I.	O	escopo	de	uma	variável	de	programa	é	a	faixa	de	instruções
na	 qual	 a	 variável	 é	 visível.	 Uma	 variável	 é	 visível	 em	 uma
instrução	se	puder	ser	referenciada	nessa	instrução.
II.	 Um	 registro	 é	 um	 agregado,	 possivelmente	 heterogêneo	 de
elementos,	 cujos	 elementos	 individuais	 são	 identificados	 por
nomes.
III.	 Um	 array	 é	 um	 agregado	 heterogêneo	 de	 elementos	 de
dados,	 cujo	 elemento	 individual	 é	 identificado	 por	 sua	 posição
em	relação	ao	primeiro.
IV.	Um	tipo	Ponteiro	é	aquele	em	que	as	variáveis	têm	uma	faixa
de	 valores	 que	 consiste	 em	 uma	 string	 ou	 coleção	 de
caracteres	e	um	valor	especial	denominado	Null.
Indique	a	opção	que	contenha	todas	as	afirmações	verdadeiras.
a)	I	e	II
b)	II	e	III
c)	III	e	IV
d)	I	e	III
e)	II	e	IV
	
PRÁTICOS
1.	 Execute	o	programa	abaixo	passo	a	passo	no	compilador	e	registre	em
papel	os	endereços	alocados	para	cada	variável	(inclusive	os	ponteiros).
Observe	 o	 que	 acontece	 no	 decorrer	 do	 programa	 e	 no	 final.	 Tente
entender	 o	 que	 o	 programa	 faz	 e	 explique	 porque	 acontece	 o	 erro	 de
execução	ao	final.
	
#	include	<stdio.h>
int	main	()
{
int	x,	*p,	*q,	i,	k=0;
q	=	p	=	&x;
for	(i=1;	i	<=	3;	i++)
{
scanf	("%d",	p);
p++;
}
p--;
while	(p	>=	q)
{
k	=	k	+	*p;
p--;
}
printf	("%d",	k);
}
	
Inverta	a	ordem	de	declaração	das	variáveis	e	observe	o	que	acontece.
	
1.	 Uma	 das	 utilidades	 de	 um	 ponteiro	 é	 de	 permitir	 a	 uma	 subrotina
retornar	mais	de	um	valor	para	suas	computações	(se	comunicando	com
variáveis	externas	a	subrotina).	Codifique	uma	subrotina	que	receba	um
número	inteiro	representando	um	total	de	segundos	e	o	endereço	para
duas	variáveis	(também	inteiras)	para	guardar	a	quantida	de	minutos	e
de	horas.	A	subrotina	deve	decompor	o	número	de	segundos	recebidos
em	um	total	de	horas	e	um	total	de	minutos,	 retornando	estes	valores
através	 dos	 endereços	 de	 variáveis	 recebidos	 como	 parâmetro.
Codifique	também	uma	função	main	que	use	a	subrotina	de	conversão.
	
2.	 Codifique	uma	subrotina	que	receba	um	vetor	de	 inteiros	e	o	endereço
de	duas	variáveis	 (também	inteiras).	O	objetivo	da	subrotina	é	procurar
neste	 vetor	 o	 menor	 e	 maior	 valor	 e	 armazená-los	 nas	 variáveis
apontadas	pelos	endereços	de	memória	recebidos.

Outros materiais