paulo1205
(usa Ubuntu)
Enviado em 29/12/2014 - 00:52h
danielcrvg escreveu:
Eu entendi que um vetor de caracteres, por si so ja representa um ponteiro, e que aponta para o primeiro endereco do bloco do char, ou seja de indice '0'.
É importante notar algumas diferenças. Um array não representa um ponteiro. Um nome de array carrega consigo, durante a compilação, mais do que simplesmente o primeiro endereço do bloco de memória, mas também informações sobre o tipo de seus elementos e sobre a quantidade de elementos. Outra característica de arrays é que o compilador não cria um espaço junto às variáveis do programa para armazenar o endereço do primeiro elemento: na hora em que reserva espaço para os elementos, o compilador já sabe o endereço desse espaço, de modo que toda ver que aparecer o nome do array, o compilador vai substituí-lo imediatamente com o valor do endereço do primeiro elemento, como se esse valor fosse uma constante do programa (calculada no momento em que o array é declarado). É por isso que um array, após ter sido declarado e/ou definido com seus valores iniciais, não pode receber outros valores ou designar uma outra área (imagine se o compilador deixaria você mudar o valor de uma constante, como, por exemplo, fazer “2=1”!). É por isso também que não faz muito sentido usar o operador
& (que serve para obter durante a execução do programa o endereço em que uma variável é armazenada) sobre o nome de um array (imagine se faria sentido dizer “&3.14159265”!).
Ponteiros, por outro lado, são variáveis que armazenam endereços. Mas não qualquer endereço: o compilador carrega informação sobre o tipo de dado para o qual a variável pode apontar junto com ela, de modo a garantir que ela realmente só aponte para objetos desse tipo e não, por acidente, para dados de algum outro tipo, nem se confunda com um valor inteiro qualquer.
De novo: ponteiro é a variável, e seu valor é sempre um endereço. Às vezes até se diz -- e eu infelizmente me incluo entre os que às vezes dizem assim, inclusive nas mensagens que postei acima -- algo do tipo “o valor da expressão é um ponteiro para
xyz ”, mas isso é tecnicamente impreciso. Melhor seria dizer que “o valor da expressão é o endereço de um objeto
xyz ”. Agora sim, ponteiros e arrays se parecem um pouco mais: quando são parte de uma expressão, tanto o nome array quanto o de uma variável ponteiro são substituídos pelos respectivos valores (constante no caso de um array, obtido do que está na variável para um ponteiro) e, salvo no caso de a expressão envolver o operador
sizeof diretamente sobre o nome, o tipo do valor nessa expressão é, para ambos, justamente “endereço de um objeto
xyz ”.
É por isso que você pode ter, por exemplo, algo como
char *pc;
char ac[6]="Teste";
pc=ac;
: quando
ac aparece no lado direito da atribuição, o nome é substituído pelo valor logicamente constante (porque é um array) cujo tipo é “endereço de objeto do tipo
char ”, que é justamente o tipo de valor que uma variável do tipo ponteiro para
char aceita manipular.
Quando vc faz esta declaracao:
char ac[10]; /* ac aponta para bloco com dez caracteres */
pc=ac; /* OK: pont. p/ char recebe endereço (i.e. pont.) do 1º
elemento do bloco de chars */
ppc=ac; /* ERRO: pont. p/ pont. p/ char não deve receber pont. p/
1º elemento do bloco de chars */
Por que um ponteiro pode receber o primeiro endereco do bloco, e um pont para pont nao pode?
Compatibilidade de tipos. O tipo de valores representados por
pc e
ac é o mesmo, e é “endereço de objeto do tipo
char ”. Já
ppc espera valores do tipo “endereço de objeto do tipo ‘
char * ’” (i.e. “endereço de objeto do tipo ponteiro para
char ”).
Outro ponto seria assim:
O operador & indica o endereco daquela variavel na memoria:
int num= 1;
int *pnum;
pnum = # /* Aqui estou apontando para variavel num, passando o endereco dela com o & */
- Se eu quero acessar esta variavel fora da funcao main(), a fim de poder manipular o conteudo dela como eu faria? Eu devo passar assim: funcao(num), funcao(int *num) ou funcao(&num)
Passagem de argumentos em C é
sempre por valor, i.e. o compilador obtém cópias dos valores de cada argumento e as submete para a função invocada. A função pode até alterar os argumentos recebidos, mas como eles são meras cópias, os valores dos objetos originais serão preservados quando a função acabar.
Parte da importância e ubiquidade de ponteiros em C é justamente devido a isso. Quando você passa um valor de endereço como argumento para uma função, mesmo sendo uma mera cópia do valor de uma variável ponteiro ou do endereço constante designado por um nome de array, essa cópia de valor de endereço pode ser usada para chegar ao mesmo dado designado pelo valor de endereço original -- o
valor de endereço é o mesmo, dentro ou fora da função. Desse modo, se você aplicar o operador
* (lê-se “conteúdo de”) ou o operador de indexação (
[] ) sobre o endereço recebido, poderá manipular o conteúdo do objeto que reside em tal endereço.
Então, se você tem um objeto designado por
num e deseja manipulá-lo noutra função, pode obter o valor do seu endereço expressando
&num . Se você assim se expressar ao passar um argumento de função, ela vai receber uma cópia desse valor.
- Se ela fosse um char, ao inves de ser um inteiro, a passagem seria do mesmo jeito?
Sim. O funcionamento é o mesmo para qualquer tipo de objeto apontado.
(Algumas pessoas confundem
char e
string . Espero que não seja o seu caso.)
- E após eu dar um free() nela, eu ainda posso manipular o conteudo dela fora da funcao main() ?
Você pode brincar com um brinquedo que deu de presente? Pode dirigir um carro que já vendeu? Pode usar uma roupa que jogou no lixo?
O brinquedo dado, o carro vendido e a roupa posta no lixo continuam existindo depois de saírem da sua mão. Então, tecnicamente falando, você até
pode conseguir algum meio de usá-los. Mas deveria? Respectivamente, a criança pode chorar, o novo dono do carro pode prestar queixa à polícia, ou você pode acabar doente.
Do mesmo modo, a memória liberada pelo programa continua existindo dentro do computador. Porém, ao liberá-la você diz ao sistema que não a quer mais, e a entrega para que ela faça com ela o uso que bem entender. Se você a quiser, não diga que não a quer. Se disser que não a quer, não pense de novo em querê-la nem tente mexer mais com ela, pois não é mais sua.
Se insistir, esteja preparado para consequências desagradáveis. Acima, eu já mostrei algumas delas.