Ir ao conteúdo
  • Cadastre-se

C Arrays com Funções - Não sei o que aconteceu no meu código


Sun__
Ir à solução Resolvido por Ansi C,

Posts recomendados

Eae, tem uma coisa que não estou entendendo em C, vou exemplificar com um código:


 

#include <stdio.h>
#include <stdlib.h>
void test(int testt[]);

int main(void) {
	int y[] = {0, 2, 3, 4};

	printf("%i\n", y[0]);
	
	test(y);

	printf("%i", y[0]);
	return 0;
}
void test(int testt[]) {
	testt[0] = 20;
}


RETORNO:
0
20

 

-> Não fez sentido nenhum pra mim ter retornado esse 20 em cima do "y[0]" sendo que eu tinha mudado o "testt[0]", por isso queria saber se existe algum tipo de linkagem em cima dos arrays em C quando são passados como argumentos?!

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

  • Solução

São nomes diferentes para um argumento. O argumento nesse exemplo é o endereço, na memória, do primeiro elementos da variável indexável (vetor) 'y'.

 

int y[] = {0, 2, 3, 4}; test(int testt[]) --> int testt []
                                   ^--------> é só outro nome para int *testt
                                   |
                                   +--------> test(y): test (int *tesst= y)
                                                   ^-------------------= &(y[0])

   +-------+-------+-------+-------+
y  |   0   |   2   |   3   |   4   |
^  +-------+-------+-------+-------+
|     ^
|     |
+-----+---> 0x100407000
      |
      +------> &(y[0])= 0x100407000
             |
             +------> &(y[1])= 0x100407004
                      |
                      +------> &(y[2])= 0x100407008
                             |
                             +------> &(y[3])= 0x10040700c

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

2 horas atrás, Sun__ disse:

Não fez sentido nenhum pra mim ter retornado esse 20 em cima do "y[0]" sendo que eu tinha mudado o "testt[0]", por isso queria saber se existe algum tipo de linkagem em cima dos arrays em C quando são passados como argumentos?!

 

Não existe nada além da linguagem. O que o Link vai entender é que a função 

 

void test(int testt[]);

 

recebe um argumento do tipo int[]. O endereço de um vetor de int. Então a função altera o valor através do ponteiro.

 

Veja o resultado de seu programa um pouco alterado e acho que vai entender melhor:

 

#include <stdio.h>
#include <stdlib.h>
void test(int testt[]);

int main(void) {
	int y[] = { 1, 2, 3, 4 };
	int z[] = { 5,6,7,8 };

	printf("y antes %i %i %i %i\n", y[0], y[1], y[2], y[3]);
	printf("z antes %i %i %i %i\n", z[0], z[1], z[2], z[3]);

	test(y);
	test(z);

	printf("y depois %i %i %i %i\n", y[0], y[1], y[2], y[3]);
	printf("y depois %i %i %i %i\n", z[0], z[1], z[2], z[3]);
	return 0;
}
void test(int testt[])
{
	testt[0] = 20;
	testt[3] = 220;
}

 

que mostra

 

y antes 1 2 3 4
z antes 5 6 7 8
y depois 20 2 3 220
y depois 20 6 7 220

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

1 hora atrás, mauro_b disse:

São nomes diferentes para um argumento. O argumento nesse exemplo é o endereço, na memória, do primeiro elementos da variável indexável (vetor) 'y'.

 


int y[] = {0, 2, 3, 4}; test(int testt[]) --> int testt []
                                   ^--------> é só outro nome para int *testt
                                   |
                                   +--------> test(y): test (int *tesst= y)
                                                   ^-------------------= &(y[0])

   +-------+-------+-------+-------+
y  |   0   |   2   |   3   |   4   |
^  +-------+-------+-------+-------+
|     ^
|     |
+-----+---> 0x100407000
      |
      +------> &(y[0])= 0x100407000
             |
             +------> &(y[1])= 0x100407004
                      |
                      +------> &(y[2])= 0x100407008
                             |
                             +------> &(y[3])= 0x10040700c

 

o que você ta dizendo é que quando passo o argumento de um array ele meio que vira um ponteiro para esse array? 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

1 hora atrás, Sun__ disse:

o que você ta dizendo é que quando passo o argumento de um array ele meio que vira um ponteiro para esse array

 

1 hora atrás, arfneto disse:

void test(int testt[]);

 

Como eu disse, o argumento de testt() é do tipo int[], um ponteiro para um array de int. Essa é a nomenclatura. A função recebe isso, o endereço de um vetor de int. Se é isso que tem do outro lado vai depender da lógica do seu programa. Em C é assim. 
 

Seu programa está ok.

 

Entendeu a diferença entre esse e o programa que mostrei? Chamando duas vezes testt() com dois vetores diferentes? 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

1 hora atrás, arfneto disse:

 

 

Como eu disse, o argumento de testt() é do tipo int[], um ponteiro para um array de int. Essa é a nomenclatura. A função recebe isso, o endereço de um vetor de int. Se é isso que tem do outro lado vai depender da lógica do seu programa. Em C é assim. 
 

Seu programa está ok.

 

Entendeu a diferença entre esse e o programa que mostrei? Chamando duas vezes testt() com dois vetores diferentes? 

Entendi sim, mas só uma pergunta, tem como eu burlar isso ou sempre que eu passar um argumento de array em uma função ele vai recebver um ponteiro para um array? Tipo, teria como eu receber a informação do array somente e mudar em uma variavel local sem alterar o que foi passado como argumento na função ou so daria certo assim mesmo, mudando as duas coisas por meio do ponteiro?

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@Sun__     se você enviou o vetor para a função e lá modificou o valor de uma de suas posições , é lógico que ao retornar a main , o valor naquela posição do vetor estará com o valor que você colocou nela lá na função , pois o vetor é o mesmo ,  não vejo nada de anormal nisso ,não .

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

32 minutos atrás, Sun__ disse:

tem como eu burlar isso ou sempre que eu passar um argumento de array em uma função ele vai recebver um ponteiro para um array?

 

Não. Não tem. Passar um array como argumento significa passar o endereço. 
 

32 minutos atrás, Sun__ disse:

teria como eu receber a informação do array somente e mudar em uma variavel local sem alterar o que foi passado como argumento na função ou so daria certo assim mesmo, mudando as duas coisas por meio do ponteiro

 

Sim.

 

Isso que chama passagem de parâmetros por valor --- copiando --- ou por referência --- o ponteiro.
 

Você pode declarar
 

void test(int const testt[])

 

e aí os valores não poderão ser alterados na função. e se declarar
 

void test(const int const testt[]);

 

indica que testt não pode ser usado para apontar para qualquer outra coisa.

 

Mas se quer alterar localmente entenda que:

 

Em geral não se quer passar uma cópia de um vetor porque há um atraso potencialmente muito grande copiando o vetor todo para a função. E por outro lado na maioria dos casos o que se quer é de fato operar com o array dentro da função. 

Se passar o array por valor tudo o que fizer com ele morre lá dentro da função. Claro, pode ser uma função sintética, como computar um valor a partir do array e retornar. 

 

De todo modo eis um exemplo de como passar o tal array por valor, que mostra
 

y antes 1 2 3 4
z antes 5 6 7 8
y depois 20 2 3 220
y depois 20 6 7 220
vetor na estrutura antes 9 10 11 12
vetor dentro da estrutura 20 10 11 220
vetor na estrutura depois 9 10 11 12

 

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

typedef struct
{
	int y[4];

}   Pacote;

void test(const int const testt[]);
void test_st(Pacote pct);

int main(void) {
	int y[] = { 1, 2, 3, 4 };
	int z[] = { 5,6,7,8 };

	printf("y antes %i %i %i %i\n", y[0], y[1], y[2], y[3]);
	printf("z antes %i %i %i %i\n", z[0], z[1], z[2], z[3]);

	test(y);
	test(z);

	printf("y depois %i %i %i %i\n", y[0], y[1], y[2], y[3]);
	printf("y depois %i %i %i %i\n", z[0], z[1], z[2], z[3]);

	Pacote p;
	p.y[0] = 9;
	p.y[1] = 10;
	p.y[2] = 11;
	p.y[3] = 12;

	printf("vetor na estrutura antes\
 %i %i %i %i\n", p.y[0], p.y[1], p.y[2], p.y[3]);
	test_st(p);
	printf("vetor na estrutura depois\
 %i %i %i %i\n", p.y[0], p.y[1], p.y[2], p.y[3]);

	return 0;
}
void test(int testt[])
{
	testt[0] = 20;
	testt[3] = 220;
}

void test_st(Pacote pct)
{
	pct.y[0] = 20;
	pct.y[3] = 220;
	printf("vetor dentro da estrutura\
 %i %i %i %i\n",
		pct.y[0], pct.y[1],
		pct.y[2], pct.y[3]);
};

 

não se trata de "burlar" nada. Apenas passar uma estrutura por valor, com o array dentro dela.

 

 

  • Curtir 2
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Em 12/10/2020 às 23:13, arfneto disse:

 

Não. Não tem. Passar um array como argumento significa passar o endereço. 
 

 

Sim.

 

Isso que chama passagem de parâmetros por valor --- copiando --- ou por referência --- o ponteiro.
 

Você pode declarar
 


void test(int const testt[])

 

e aí os valores não poderão ser alterados na função. e se declarar
 


void test(const int const testt[]);

 

indica que testt não pode ser usado para apontar para qualquer outra coisa.

 

Mas se quer alterar localmente entenda que:

 

Em geral não se quer passar uma cópia de um vetor porque há um atraso potencialmente muito grande copiando o vetor todo para a função. E por outro lado na maioria dos casos o que se quer é de fato operar com o array dentro da função. 

Se passar o array por valor tudo o que fizer com ele morre lá dentro da função. Claro, pode ser uma função sintética, como computar um valor a partir do array e retornar. 

 

De todo modo eis um exemplo de como passar o tal array por valor, que mostra
 


y antes 1 2 3 4
z antes 5 6 7 8
y depois 20 2 3 220
y depois 20 6 7 220
vetor na estrutura antes 9 10 11 12
vetor dentro da estrutura 20 10 11 220
vetor na estrutura depois 9 10 11 12

 


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

typedef struct
{
	int y[4];

}   Pacote;

void test(const int const testt[]);
void test_st(Pacote pct);

int main(void) {
	int y[] = { 1, 2, 3, 4 };
	int z[] = { 5,6,7,8 };

	printf("y antes %i %i %i %i\n", y[0], y[1], y[2], y[3]);
	printf("z antes %i %i %i %i\n", z[0], z[1], z[2], z[3]);

	test(y);
	test(z);

	printf("y depois %i %i %i %i\n", y[0], y[1], y[2], y[3]);
	printf("y depois %i %i %i %i\n", z[0], z[1], z[2], z[3]);

	Pacote p;
	p.y[0] = 9;
	p.y[1] = 10;
	p.y[2] = 11;
	p.y[3] = 12;

	printf("vetor na estrutura antes\
 %i %i %i %i\n", p.y[0], p.y[1], p.y[2], p.y[3]);
	test_st(p);
	printf("vetor na estrutura depois\
 %i %i %i %i\n", p.y[0], p.y[1], p.y[2], p.y[3]);

	return 0;
}
void test(int testt[])
{
	testt[0] = 20;
	testt[3] = 220;
}

void test_st(Pacote pct)
{
	pct.y[0] = 20;
	pct.y[3] = 220;
	printf("vetor dentro da estrutura\
 %i %i %i %i\n",
		pct.y[0], pct.y[1],
		pct.y[2], pct.y[3]);
};

 

não se trata de "burlar" nada. Apenas passar uma estrutura por valor, com o array dentro dela.

 

 

saquei, não estudei estruturas em C ainda, mas analisando o codigo deu pra ter uma ideia do que aconteceu, ajudou bastante cara, valeu mesmo :)

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

Em 12/10/2020 às 19:44, Sun__ disse:

o que você ta dizendo é que quando passo o argumento de um array ele meio que vira um ponteiro para esse array? 

 

Eu meio que conduzi esse entendimento, porém o esquema mostra que 'vira' o argumento (valor) para um variável do tipo ponteiro que é um parâmetro da função.

Em 12/10/2020 às 17:46, mauro_b disse:

São nomes diferentes para um argumento. O argumento nesse exemplo é o endereço, na memória, do primeiro elementos da variável indexável (vetor) 'y'

 

Está esquematizado que 'y' é só um nome para um endereço, diferente de variável ponteiro. Ponteiro é uma variável (não primitiva) que recebe valores, logo a passagem por referência é uma ilusão, somente há passagem por valor. No caso especial dos ponteiros o valor é um endereço.

Em 12/10/2020 às 17:46, mauro_b disse:

 





int y[] = {0, 2, 3, 4}; test(int testt[]) --> int testt []
                                   ^--------> é só outro nome para int *testt
                                   |
                                   +--------> test(y): test (int *tesst= y)
                                                   ^-------------------= &(y[0])

   +-------+-------+-------+-------+
y  |   0   |   2   |   3   |   4   |
^  +-------+-------+-------+-------+
|     ^
|     |
+-----+---> 0x100407000
      |
      +------> &(y[0])= 0x100407000
             |
             +------> &(y[1])= 0x100407004
                      |
                      +------> &(y[2])= 0x100407008
                             |
                             +------> &(y[3])= 0x10040700c

 

 

*Variáveis tem nome, tipo, valor e endereço. 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

1 hora atrás, mauro_b disse:

Está esquematizado que 'y' é só um nome para um endereço, diferente de variável ponteiro. Ponteiro é uma variável (não primitiva) que recebe valores, logo a passagem por referência é uma ilusão, somente há passagem por valor. No caso especial dos ponteiros o valor é um endereço

 

Não é o caso. y é int[]

 

Arrays são sempre passados por referência e essa questão por exemplo começou com essa dúvida:

 

Em 12/10/2020 às 16:48, Sun__ disse:

Não fez sentido nenhum pra mim ter retornado esse 20 em cima do "y[0]" sendo que eu tinha mudado o "testt[0]", por isso queria saber

 

E o valor em main() apareceu alterado porque o argumento y foi passado por referência. E é assim em C. Assim começou esse tópico.

 

Estamos falando desse código
 

void test(int testt[]);

int main(void) {
	int y[] = {0, 2, 3, 4};

	printf("%i\n", y[0]);
	
	test(y);

	printf("%i", y[0]);
	return 0;
}
void test(int testt[]) {
	testt[0] = 20;
}

 

Onde y é int[] e vai ser passado por referência. E por isso qualquer alteração de testt[] na função test() tem efeito nos valores acessados em main() depois do retorno, o vetor y ou os vetores y e z no caso do exemplo que mostrei.

 

 

11 horas atrás, Sun__ disse:

saquei, não estudei estruturas em C ainda, mas analisando o codigo deu pra ter uma ideia do que aconteceu

 

@Sun__ tem razão: sempre analise o código antes de tirar qualquer conclusão, ou escreva um programa de teste. Um parágrafo solto num post pode gerar muita dúvida e confusão, sem qualquer exemplo ou teste... ;) 

 

Como está no programa de exemplo, a maneira de passar um array por valor apareceu depois da introdução de struct em C.

 

1 hora atrás, mauro_b disse:

Ponteiro é uma variável (não primitiva) que recebe valores, logo a passagem por referência é uma ilusão

 

Não, não é. entenda que é passado um ponteiro. O endereço de início do vetor. Atente para o exemplo que eu mostrei, onde DOIS vetores são passados por referência e alterados em main() e um terceiro é alterado localmente na função e aparece inalterado no retorno... O código compilável está acima no tópico #8...
 

y antes 1 2 3 4
z antes 5 6 7 8
y depois 20 2 3 220
y depois 20 6 7 220
vetor na estrutura antes 9 10 11 12
vetor dentro da estrutura 20 10 11 220
vetor na estrutura depois 9 10 11 12

 

 

Passagem por valor


No caso da passagem por valor os argumentos são todos copiados no stack e passados para a função a cada chamada. Nesse exemplo, fosse aqui um programa em Pascal se poderia passar os 4 int de y para a função test() e ela teria sua  copia local. Em C o que é passado é um ponteiro, que poderia ser lido como int*, mas declarado como int[]. arrays são passados por referência em C e diferenças entre ponteiros e arrays são mesmo uma fonte de confusão para iniciantes e mesmo profissionais em C.

 

Um novo exemplo com os endereços e a passagem por referência e por valor:

 

Alterei o exemplo que eu tinha deixado, para mostrar os endereços dos vetores em main() e nas funções no caso de passagem por valor e por referência. Eu devia ter escrito assim inicialmente ;) 

 

Saída
 

y antes 1 2 3 4 Endereco de y: 0000005E866FF888
z antes 5 6 7 8 Endereco de z: 0000005E866FF8B8

chamando test() com vetor y
Vetor 'testt' dentro de test(): 20 2 3 220 Endereco de testt: 0000005E866FF888

chamando test() com vetor z
Vetor 'testt' dentro de test(): 20 6 7 220 Endereco de testt: 0000005E866FF8B8

y depois 20 2 3 220
y depois 20 6 7 220

vetor 'p' na estrutura antes 9 10 11 12. Endereco: 0000005E866FF8E8
vetor 'pct' dentro da estrutura 20 10 11 220 Endereco: 0000005E866FF910
vetor na estrutura depois 9 10 11 12


O Programa

 

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

typedef struct
{
	int y[4];

}   Pacote;

void test(int testt[]);
void test_st(Pacote pct);

int main(void) {
	int y[] = { 1, 2, 3, 4 };
	int z[] = { 5,6,7,8 };

	printf("y antes %i %i %i %i Endereco de y: %p \n", 
		y[0], y[1], y[2], y[3],
		y);
	printf("z antes %i %i %i %i Endereco de z: %p\n",
		z[0], z[1], z[2], z[3],
		z );

	printf("\nchamando test() com vetor y\n");
	test(y);

	printf("\nchamando test() com vetor z\n");
	test(z);

	printf("\ny depois %i %i %i %i\n", y[0], y[1], y[2], y[3]);
	printf("y depois %i %i %i %i\n", z[0], z[1], z[2], z[3]);

	Pacote p;
	p.y[0] = 9;
	p.y[1] = 10;
	p.y[2] = 11;
	p.y[3] = 12;

	printf("\nvetor 'p' na estrutura antes\
 %i %i %i %i. Endereco: %p\n",
		p.y[0], p.y[1], p.y[2], p.y[3],
		&p);
	test_st(p);
	printf("vetor na estrutura depois\
 %i %i %i %i\n", p.y[0], p.y[1], p.y[2], p.y[3]);

	return 0;
}
void test(int testt[])
{
	testt[0] = 20;
	testt[3] = 220;
	printf("Vetor 'testt' dentro de test(): %i %i %i %i Endereco de testt: %p\n",
		testt[0], testt[1], testt[2], testt[3],
		testt);
}

void test_st(Pacote pct)
{
	pct.y[0] = 20;
	pct.y[3] = 220;
	printf("vetor 'pct' dentro da estrutura\
 %i %i %i %i Endereco: %p\n",
		pct.y[0], pct.y[1],
		pct.y[2], pct.y[3],
		&pct);
};

 

 

E assim pode ver que test() recebe um ponteiro para o vetor a cada chamada. E no caso da struct o endereço da estrutura Pacote na função é diferente e deixa de existir a cada chamada, já que a estrutura aí sim é passada por valor.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

3 horas atrás, arfneto disse:

Não é o caso. y é int[]

Dessa vez é um erro de interpretação, mas é que não há como erra na interpretação porque fui suficientemente claro, ainda assim, surge um ou outro qualquer que não vai conseguir, ou fingir não entender.

 

Quando declaramos  o vetor 

int array []= {1,2,3,4}; // array é tipo int []

 

No (situação) argumento da função é um endereço para o primeiro elemento, assim já citado 

int y[] = {0, 2, 3, 4}; test(int testt[]) --> int testt []
                                   ^--------> é só outro nome para int *testt
                                   |
                                  +--------> test(y): test (int *tesst= endereco do primeiro elemento)
                                                   ^------------------= &(y[0]) OU y

 

 

3 horas atrás, arfneto disse:

Arrays são sempre passados por referência e essa questão por exemplo começou com essa dúvida

Não o array, mas sim o ENDEREÇO do primeiro elemento do array que são duas coisas. Por exemplo, o operador sizeof não operaria o array, dentro da função, porém sim o ponteiro que é o parâmetro da função com cópia do endereço do primeiro elemento do array (porém não o array).

 

Até os mais experientes tem dificuldade para aceitar esse fato. Em C as passagens são de valor, às vezes, ponteiros são chamados de referências esse é o motivo da confusão que alguns fazem, mas é tudo uma ilusão. A passagem (cópia de argumentos) em C são de valores e um ponteiro é uma variável (especial) que carrega o endereço, que por vezes são chamadas de referências.

 

3 horas atrás, arfneto disse:

Não, não é. entenda que é passado um ponteiro. O endereço de início do vetor. Atente para o exemplo que eu mostrei, onde DOIS vetores são passados por referência e alterados em main() e um terceiro é alterado localmente na função e aparece inalterado no retorno... O código compilável está acima no tópico #8...

 

Entendo que cometeu um erro de interpretação, observe mais atentamente o esquema que está tudo suficientemente claro;

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

41 minutos atrás, mauro_b disse:

Em C as passagens são de valor, às vezes, ponteiros são chamados de referências esse é o motivo da confusão que alguns fazem, mas é tudo uma ilusão.

 

:) está bem. 

 

em java por exemplo  ponteiros são chamados de ... references. Um ponteiro é exatamente uma referência e o próprio termo call by reference significa passar o endereço dos argumentos e não o valor. 

 

Mas uma referência também é claro um valor e não há conteúdo nesse jogo de palavras: algum valor vai ser passado. Se for o valor do argumento trata-se de call by value, se for o endereço trata-se de call by reference.

 

É o que pode ver no programa que mostrei. Lá pode ver que os endereços da struct mudam no caso de passagem por valor, e não mudariam se ela tivesse sido passada por referência...

 

bastaria alterar a declaração de 

 

    void test_st(Pacote pct);

 

para 

 

    void test_st(Pacote* pct);

 

 e usar os operadores corretos dentro da função. Imagino que se possa chamar isso de qualquer nome. Mas é como funciona e pode ser visto no programa.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

27 minutos atrás, arfneto disse:

em java por exemplo  ponteiros são chamados de ... references. Um ponteiro é exatamente uma referência e o próprio termo call by reference significa passar o endereço dos argumentos e não o valor. 

Mas diferente do que a maioria tende a difundir, a cópia e do valor no ponteiro (ou referência), porém não o ponteiro. Caso contrário em que a cópia fosse do ponteiro teríamos um alias (outro nome) para o endereço,ou para um ponteiro.

 

No caso, ao comandar: testt= 0x0, trocaríamos o endereço do primeiro elemento de array também para 0, porque nessa hipótese, que nada tem a ver com os fatos em C, testt é outro nome para array dentro da função

 

.

 

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

11 minutos atrás, mauro_b disse:

Mas diferente do que a maioria tende a difundir, a cópia acontece com valor no ponteiro (ou referência), porém não o ponteiroo. Caso a cópia fosse do ponteiro teríamos um alias (outro nome).

 

  • No caso, ao comandar: testt= 0x0, trocaríamos o endereço do primeiro elemento de array também para 0, porque nessa hipótese, que nada tem a ver com os fatos em C, testt é outro nome para array dentro da função

 

essas coisas não nossa "difusão" ou opinião.  Linguagens de programação são coisas estabelecidas. Você pode aprender, testar, ensinar, e mesmo opinar até um certo ponto já que há normas e programas rodando.

 

Se referindo ao programa alvo do tópico, é claro que

 

void test(int testt[])
{ 
  testt[0] = 20;
}

 

testt é int[] um ponteiro para um vetor de int. E é um valor somente leitura. Não pode apontar para outra coisa. É como se o protótipo da função fosse 
 

    void test_2(int* const testt);


escrever 

 

    testt = 0x0; // o rebuscado
// ou
    testt = 0; // o simples, já que zero é zero
    // tambem em decimal ou qualquer outra base

 

como escreveu vai cancelar seu programa apenas: 

 

testt é uma referência para o valor passado, como no programa de exemplo, nesse trecho:
 

	int y[] = { 1, 2, 3, 4 };
	int z[] = { 5,6,7,8 };

	printf("y antes %i %i %i %i Endereco de y: %p \n", 
		y[0], y[1], y[2], y[3],
		y);
	printf("z antes %i %i %i %i Endereco de z: %p\n",
		z[0], z[1], z[2], z[3],
		z );

	printf("\nchamando test() com vetor y\n");
	test(y);

	printf("\nchamando test() com vetor z\n");
	test(z);

 

na primeira chamada é uma referência para y, na segunda uma referência para z, o que pode ver simplesmente rodando o programa em sua máquina. E pode entender que quando a struct é passada por valor as alterações feitas na função não permanecem depois do retorno. Só nesse caso.

 

Mas testt pode e está sendo usado na única linha da função, para atribuir o valor 20 ao primeiro int  do vetor cujo endereço foi enviado como argumento da função. Usado como referência. E funciona assim.

 

Outra maneira de escrever test():
 

void test_2( int* const testt)
{
	testt[0] = -20;
	testt[3] = -220;
	int outro = 0;
	//testt = &outro; // aqui daria erro: testt nao pode apontar para outra coisa
	printf("test2(): Vetor 'testt' dentro de test(): %i %i %i %i Endereco de testt: %p\n",
		testt[0], testt[1], testt[2], testt[3],
		testt);
}

 

 

e note que a atribuição como você escreveu está lá comentada. Pode rodar em máquina sem o comentário e se compilar vai notar que o programa cancela naquela linha...

 

Independendo de nossa opinião o programa cancela naquela linha: testt é int[] ou int* const.  E assim não pode ser alterado.

 

A saída do exemplo alterado
 

y antes 1 2 3 4 Endereco de y: 0000007B414FF978
z antes 5 6 7 8 Endereco de z: 0000007B414FF9A8

chamando test() com vetor y
Vetor 'testt' dentro de test(): 20 2 3 220 Endereco de testt: 0000007B414FF978

chamando test() com vetor z
Vetor 'testt' dentro de test(): 20 6 7 220 Endereco de testt: 0000007B414FF9A8

y depois 20 2 3 220
y depois 20 6 7 220

chamando test_2() (usando ponteiro) com vetor z
test2(): Vetor 'testt' dentro de test(): -20 6 7 -220 Endereco de testt: 0000007B414FF9A8

vetor 'p' na estrutura antes 9 10 11 12. Endereco: 0000007B414FF9D8
vetor 'pct' dentro da estrutura 20 10 11 220 Endereco: 0000007B414FFA00
vetor na estrutura depois 9 10 11 12

 

O programa

 

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

typedef struct
{
	int y[4];

}   Pacote;

void test(int testt[]);
void test_2(int* testt);
void test_st(Pacote pct);

int main(void) {
	int y[] = { 1, 2, 3, 4 };
	int z[] = { 5,6,7,8 };

	printf("y antes %i %i %i %i Endereco de y: %p \n", 
		y[0], y[1], y[2], y[3],
		y);
	printf("z antes %i %i %i %i Endereco de z: %p\n",
		z[0], z[1], z[2], z[3],
		z );

	printf("\nchamando test() com vetor y\n");
	test(y);

	printf("\nchamando test() com vetor z\n");
	test(z);

	printf("\ny depois %i %i %i %i\n", y[0], y[1], y[2], y[3]);
	printf("y depois %i %i %i %i\n", z[0], z[1], z[2], z[3]);

	// chamando usando o ponteiro
	printf("\nchamando test_2() (usando ponteiro) com vetor z\n");
	test_2(z);

	Pacote p;
	p.y[0] = 9;
	p.y[1] = 10;
	p.y[2] = 11;
	p.y[3] = 12;

	printf("\nvetor 'p' na estrutura antes\
 %i %i %i %i. Endereco: %p\n",
		p.y[0], p.y[1], p.y[2], p.y[3],
		&p);
	test_st(p);
	printf("vetor na estrutura depois\
 %i %i %i %i\n", p.y[0], p.y[1], p.y[2], p.y[3]);

	return 0;
}

void test(int testt[])
{
	testt[0] = 20;
	testt[3] = 220;
	printf("Vetor 'testt' dentro de test(): %i %i %i %i Endereco de testt: %p\n",
		testt[0], testt[1], testt[2], testt[3],
		testt);
}

void test_2( int*  testt)
{
	testt[0] = -20;
	testt[3] = -220;
	int outro = 0;
	//testt = &outro; // aqui daria erro: testt nao pode apontar para outra coisa
	printf("test2(): Vetor 'testt' dentro de test(): %i %i %i %i Endereco de testt: %p\n",
		testt[0], testt[1], testt[2], testt[3],
		testt);
}

void test_st(Pacote pct)
{
	pct.y[0] = 20;
	pct.y[3] = 220;
	printf("vetor 'pct' dentro da estrutura\
 %i %i %i %i Endereco: %p\n",
		pct.y[0], pct.y[1],
		pct.y[2], pct.y[3],
		&pct);
};

 

Não sei ao certo o que quer mostrar, mas talvez você possa escrever um programa que mostre algo a respeito.

 

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

3 horas atrás, arfneto disse:

essas coisas não nossa "difusão" ou opinião.  Linguagens de programação são coisas estabelecidas. Você pode aprender, testar, ensinar, e mesmo opinar até um certo ponto já que há normas e programas rodando.

Eu pensei que um desenho seria mais acessível, me enganei, pelo visto é necessário mais que isso.

 

3 horas atrás, arfneto disse:

testt é int[] um ponteiro para um vetor de int. E é um valor somente leitura. Não pode apontar para outra coisa. É como se o protótipo da função fosse 

Como assim não pode! Isso difere de não deve, pois, pode e não será notificado a depender do nível do alerta, isso porque ao contrário de sua opinião testt uma variável do tipo ponteiro para int, apesar de sua experiência demostra não entender corretamente que um PONTEIRO PARA VETOR DE INT tem esta nomenclatura int (*) [].

 

Só um exemplo correto e adequado para ilustrar os fatos da linguagem C de programação,

main (void) {
	int vetor [10];   // Vetor do tipo int [10]
	int (*pvetor) []; // Um ponteiro para um vetor de int
  	int *p;           // ponteiro
  
	pvetor= &vetor;  // endereço de vetor ->> ponteiro de vetor
	p= vetor;        // endereço do primeiro elemento de vetor ->> ponteiro
  
}

 

Qualquer compilador com atualização em 2010 compila sem problema porque não há erros.

 

PS.: Estou caçando principalmente porque fico rodando enquanto leio "defezinhas"

 

 

 

  • Curtir 1
  • Haha 1
Link para o comentário
Compartilhar em outros sites

4 horas atrás, mauro_b disse:

Só um exemplo correto e adequado para ilustrar os fatos da linguagem C de programação


Muito bom 👍.

Claro que você, o próprio autor, julgar a correção e a adequação de seu exemplo, um "programa" de 5 comandos e que não faz nada, é estranho.

 

Citação

Vou comentar e mostrar o que fazer com o que você escreveu, colocando no contexto da discussão, porque é algo que pode ensinar a algum iniciante


Imagino que você não tenha dúvidas e só tenha  a ensinar.
 

main (void) {
	int vetor [10];   // Vetor do tipo int [10]
	int (*pvetor) []; // Um ponteiro para um vetor de int
  	int *p;           // ponteiro
  
	pvetor= &vetor;  // endereço de vetor ->> ponteiro de vetor
	p= vetor;        // endereço do primeiro elemento de vetor ->> ponteiro
  
}

 

Acho que sabe que seu exemplo não faz nada. Nem entrada, nem saída, nem passagem de parâmetros. Nem tem vínculo com o tópico. 

 

4 horas atrás, mauro_b disse:

Como assim não pode! Isso difere de não deve, pois, pode e não será notificado a depender do nível do alerta, isso porque ao contrário de sua opinião testt uma variável do tipo ponteiro para int, apesar de sua experiência demostra não entende corretamente que um PONTEIRO PARA VETOR DE INT tem esta nomenclatura int (*) []

 

Essa não é a única nomenclatura para um ponteiro para vetor de int. E de longe é a menos usada. Mas vou te mostrar que além de não fazer diferença é a menos legível e a menos conveniente :) Preste atenção ao programa que vou mostrar e verá várias outras maneiras. E vou te mostrar como escreveria essa mesma, só que dentro do contexto do tópico e não como 8 linhas soltas aqui para mostrar cultura, como pareceu que tentou fazer.

 

Então o que não pode?

 

Isso que você escreveu é o que "não pode" :) :
 

8 horas atrás, mauro_b disse:

No caso, ao comandar: testt= 0x0, trocaríamos o endereço do primeiro elemento de array também para 0, porque nessa hipótese, que nada tem a ver com os fatos em C, testt é outro nome para array dentro da função

 

Não. Não trocaríamos nada. testt é imutável. Uma constante definida em tempo de compilação dentro da função. Exatamente como seria int* const testt

Por outro lado, eu expliquei e  mostrei no programa a passagem de valores por referência e por valor. De 4 maneiras distintas. E mostrando os endereços das variáveis. Só deixei de mostrar a quinta opção, passar a estrutura por referência, porque não vi necessidade.

 

E deixei em comentário a linha de programa que você sugeriu: alterar o valor de testt dentro da função. E se tirar aquele comentário vai cancelar o programa. O seu ou o meu.

 

void test(int testt[]);
void test_2(int* testt);

 

No primeiro caso acima int[] é sim um ponteiro para int. e  o exemplo que eu deixei mostra até o endereço. No segundo caso é um ponteiro para int mas pode ser usado da mesma maneira. C foi escrita para escrever sistemas e tendo alguma maneira de saber onde termina a área alocada em testt se pode usar da mesma maneira. Em muitos casos se usa o que se chama "sentinela", algo como o zero no final de uma string

 

Entenda afinal que isso que escreveu cancelaria seu programa. "Comandar" isso, como escreveu. Como eu mostrei. Tire o comentário da linha que eu coloquei no exemplo e verá.

 

Citação

No seu exemplo "correto e adequado" você preferiu ignorar isso que havia escrito antes. E fez bem: estava errado afinal. Apenas rode o programa com a linha que sugeriu e acompanhe...

 

4 horas atrás, mauro_b disse:

PS.: Estou caçando principalmente porque fico rodando enquanto leio "defezinhas"

 

:) ficou bem melhor com o exemplo que postou! 
 

4 horas atrás, mauro_b disse:

Qualquer compilador com atualização em 2010 compila sem problema porque não há erros.

 

Sim. E cancelaria o que sugeriu escrever, mas não o seu "exemplo correto e adequado" que infelizmente nada faz.

 

Um pouco de recortar e colar no exemplo que já mostrei:

 

Vou até acrescentar aqui o exemplo que sugeriu:  uma função 
 

    void test_3(int(*)[]);

 

Acho que não escreveu um exemplo útil com isso porque talvez não saiba como acertar as declarações quando se trata de passagem de parâmetro para uma função, mas pode ter sido preguiça mesmo. De todo modo eis um exemplo:
 

void test_3(int(*testt)[])
{
	printf("Vetor 'testt' entrando em test_3():\t%4i %4i %4i %4i Endereco de testt: %p\n",
		(*testt)[0], (*testt)[1], (*testt)[2], (*testt)[3],
		testt);
	(*testt)[0] = 1;
	(*testt)[3] = 2;
	(*testt)[0] = 3;
	(*testt)[3] = 4;
	int outro = 0;
	//testt = &outro; // aqui daria erro: testt nao pode apontar para outra coisa
	printf("Vetor 'testt'  saindo  de test_3():\t%4i %4i %4i %4i Endereco de testt: %p\n",
		(*testt)[0],
		(*testt)[1],
		(*testt)[2],
		(*testt)[3],
		testt);
};

 

Talvez você não saiba que precisa dos dois operadores, * e [ ] e como a prioridade de [ ] é maior precisa TAMBÉM dos parenteses. Não deve ter pensado muito sobre isso, ou não sabia mesmo. Não há razão para usar esse formato aqui.

Claro, você pode ver alguma razão e ilustrar aqui.

 

A saída do exemplo revisado, que agora inclui sua sugestão e também a passagem da estrutura contendo o array, mas por referência
 

y antes    1    2    3    4 Endereco de y: 00EFF7A8
z antes    5    6    7    8 Endereco de z: 00EFF790

chamando test() com vetor y
Vetor 'testt' entrando em test():          1    2    3    4 Endereco de testt: 00EFF7A8
Vetor 'testt' saindo   de test():         20   21   22   23

chamando test() com vetor z
Vetor 'testt' entrando em test():          5    6    7    8 Endereco de testt: 00EFF790
Vetor 'testt' saindo   de test():         20   21   22   23

y depois   20   21   22   23
z depois   20   21   22   23

chamando test_2() (usando ponteiro) com vetor z
Vetor 'testt' entrando em test_2():       20   21   22   23 Endereco de testt: 00EFF790
Vetor 'testt' dentro  de  test_2():      -20  -19  -18  -17

chamando test_3() (usando int (*)[]) com vetor z
z antes  -20  -19  -18  -17 Endereco de z: 00EFF790
Vetor 'testt' entrando em test_3():      -20  -19  -18  -17 Endereco de testt: 00EFF790
Vetor 'testt'  saindo  de test_3():        3  -19  -18    4 Endereco de testt: 00EFF790

vetor 'p' na estrutura antes        9   10   11   12. Endereco: 00EFF778
(passagem por valor)
vetor 'pct' entrando em test_st():          9   10   11   12 Endereco: 00EFF698
vetor 'pct'  saindo de  test_st():         15   16   17   18 Endereco: 00EFF698
vetor na estrutura em main() no retorno     9   10   11   12

Passando afinal a estrutura por referencia
(passagem por referencia)
vetor 'pct' entrando em test_st2():         9   10   11   12 Endereco: 00EFF778
vetor 'pct' entrando em test_st2():        40   41   42   43
vetor na estrutura em main() no retorno    40   41   42   43

 

Só um pouco de recortar e colar afinal

 

Eis o programa

 

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

typedef struct
{
	int y[4];

}   Pacote;

void test(int testt[]);
void test_2(int* testt);
void test_3(int(*)[]);
void test_st(Pacote  pct);
void test_st2(Pacote* pct);

int main(void)
{
	int  y[] = { 1,2,3,4 };
	int  z[] = { 5,6,7,8 };

	printf("y antes %4i %4i %4i %4i Endereco de y: %p \n",
		y[0], y[1], y[2], y[3],
		y);
	printf("z antes %4i %4i %4i %4i Endereco de z: %p\n",
		z[0], z[1], z[2], z[3],
		z);

	printf("\nchamando test() com vetor y\n");
	test(y);

	printf("\nchamando test() com vetor z\n");
	test(z);

	printf("\ny depois %4i %4i %4i %4i\n", y[0], y[1], y[2], y[3]);
	printf("z depois %4i %4i %4i %4i\n", z[0], z[1], z[2], z[3]);

	// chamando usando o ponteiro
	printf("\nchamando test_2() (usando ponteiro) com vetor z\n");
	test_2(z);

	// chamando usando o ponteiro com int (*)[]
	printf("\nchamando test_3() (usando int (*)[]) com vetor z\n");
	printf("z antes %4i %4i %4i %4i Endereco de z: %p \n",
		z[0], z[1], z[2], z[3],
		z);
	test_3(&z);

	Pacote p;
	p.y[0] = 9;
	p.y[1] = 10;
	p.y[2] = 11;
	p.y[3] = 12;

	// passagem por valor

	printf("\nvetor 'p' na estrutura antes\t\
 %4i %4i %4i %4i. Endereco: %p\n",
		p.y[0], p.y[1], p.y[2], p.y[3],
		&p);
	test_st(p);
	printf("vetor na estrutura em main() no retorno\t\
 %4i %4i %4i %4i\n", p.y[0], p.y[1], p.y[2], p.y[3]);

	printf("\nPassando afinal a estrutura por referencia\n");
	test_st2(&p);
	printf("vetor na estrutura em main() no retorno\t\
 %4i %4i %4i %4i\n", p.y[0], p.y[1], p.y[2], p.y[3]);

	return 0;
}

void test(int testt[])
{
	printf("Vetor 'testt' entrando em test():\t%4i %4i %4i %4i Endereco de testt: %p\n",
		testt[0], testt[1], testt[2], testt[3],
		testt);
	testt[0] = 20;
	testt[1] = 21;
	testt[2] = 22;
	testt[3] = 23;
	printf("Vetor 'testt' saindo   de test():\t%4i %4i %4i %4i\n",
		testt[0], testt[1], testt[2], testt[3]);
}

void test_2(int* testt)
{
	printf("Vetor 'testt' entrando em test_2():\t%4i %4i %4i %4i Endereco de testt: %p\n",
		testt[0], testt[1], testt[2], testt[3],
		testt);
	testt[0] = -20;
	testt[1] = -19;
	testt[2] = -18;
	testt[3] = -17;
	int outro = 0;
	//testt = &outro; // aqui daria erro: testt nao pode apontar para outra coisa
	printf("Vetor 'testt' dentro  de  test_2():\t%4i %4i %4i %4i\n",
		testt[0], testt[1], testt[2], testt[3]);
}

void test_3(int(*testt)[])
{
	printf("Vetor 'testt' entrando em test_3():\t%4i %4i %4i %4i Endereco de testt: %p\n",
		(*testt)[0], (*testt)[1], (*testt)[2], (*testt)[3],
		testt);
	(*testt)[0] = 1;
	(*testt)[3] = 2;
	(*testt)[0] = 3;
	(*testt)[3] = 4;
	int outro = 0;
	//testt = &outro; // aqui daria erro: testt nao pode apontar para outra coisa
	printf("Vetor 'testt'  saindo  de test_3():\t%4i %4i %4i %4i Endereco de testt: %p\n",
		(*testt)[0],
		(*testt)[1],
		(*testt)[2],
		(*testt)[3],
		testt);
};

void test_st(Pacote pct)
{
	printf("(passagem por valor)\n\
vetor 'pct' entrando em test_st():\t\
 %4i %4i %4i %4i Endereco: %p\n",
		pct.y[0], pct.y[1],
		pct.y[2], pct.y[3],
		&pct);
	pct.y[0] = 15;
	pct.y[1] = 16;
	pct.y[2] = 17;
	pct.y[3] = 18;
	printf("\
vetor 'pct'  saindo de  test_st():\t\
 %4i %4i %4i %4i Endereco: %p\n",
		pct.y[0], pct.y[1],
		pct.y[2], pct.y[3],
		&pct);
};

void test_st2(Pacote* pct)
{
	printf("(passagem por referencia)\n\
vetor 'pct' entrando em test_st2():\t\
 %4i %4i %4i %4i Endereco: %p\n",
		pct->y[0], pct->y[1],
		pct->y[2], pct->y[3],
		pct);
	pct->y[0] = 40;
	pct->y[1] = 41;
	pct->y[2] = 42;
	pct->y[3] = 43;
	printf("\
vetor 'pct' entrando em test_st2():\t\
 %4i %4i %4i %4i\n",
		pct->y[0], pct->y[1],
		pct->y[2], pct->y[3]);
};

// fim

 

  • Haha 1
Link para o comentário
Compartilhar em outros sites

4 horas atrás, arfneto disse:

Muito bom 👍.

Claro que você, o próprio autor, julgar a correção e a adequação de seu exemplo, um "programa" de 5 comandos e que não faz nada, é estranho

Estranho mesmo a sua pouca capacidade de interpretar, mas não é surpresa nenhuma, haja vista que se um desenho não é o bastante então não posso ajudar. Pior, Continuo as voltas nesse postagem exatamente só por causa desse detalhe que é totalmente pessoal.

 

Mas vamos lá, como disse essa é a sintaxe e a nomenclatura corretamente adequada correspondente a fala: ponteiro para vetor de Int. Diferente do que apresentou como certo. Agora quem está se defendendo sou eu, mas nem precisaria fazer disso, se não gostou do meu exemplo o problema é seu, "vida que segue" e não pense que está me ajudando porque não está: pois, uma situação comum tão simples assim tem um exemplo igualmente simples no ponto que explora tão-somente os algoritmos de correções e alerta do compilador.

 

4 horas atrás, arfneto disse:

Acho que sabe que seu exemplo não faz nada. Nem entrada, nem saída, nem passagem de parâmetros. Nem tem vínculo com o tópico.

Mas a culpa é exclusivamente tua porque só descobre que tem algo a dizer depois que lê uma postagem e faz comentário, sem nexos, ignorando os fatos.

 

Não acontecer nada significa que os comandos estão certos, o objetivo foi esse mesmo.

9 horas atrás, mauro_b disse:

Só um exemplo correto e adequado para ilustrar os fatos da linguagem C de programação,








main (void) {
	int vetor [10];   // Vetor do tipo int [10]
	int (*pvetor) []; // Um ponteiro para um vetor de int
  	int *p;           // ponteiro
  
	pvetor= &vetor;  // endereço de vetor ->> ponteiro de vetor
	p= vetor;        // endereço do primeiro elemento de vetor ->> ponteiro
  
}

Qualquer compilador com atualização em 2010 compila sem problema porque não há erros.

 

E discordo que não existe relação com tópico, mais uma vez a interpretação. A pastagem, no momento que trata de vetores considera, mesmo que implicitamente os  ponteiros de todos os tipos, ainda assim, não há necessidade de dimensões ou nomenclatura para além de um ponteiro de int.

 

 

Devidamente esquematizado explorando os fatos.



int y[] = {0, 2, 3, 4}; test(int testt[]) --> int testt []
                                   ^--------> é só outro nome para int *testt
                                   |
                                   +--------> test(y): test (int *tesst= y)
                                                   ^-------------------= &(y[0])

   +-------+-------+-------+-------+
y  |   0   |   2   |   3   |   4   |
^  +-------+-------+-------+-------+
|     ^
|     |
+-----+---> 0x100407000
      |
      +------> &(y[0])= 0x100407000
             |
             +------> &(y[1])= 0x100407004
                      |
                      +------> &(y[2])= 0x100407008
                             |
                             +------> &(y[3])= 0x10040700c

 

 

4 horas atrás, arfneto disse:

Talvez você não saiba que precisa dos dois operadores, * e [ ] e como a prioridade de [ ] é maior precisa TAMBÉM dos parenteses. Não deve ter pensado muito sobre isso, ou não sabia mesmo. Não há razão para usar esse formato aqui.

Claro, você pode ver alguma razão e ilustrar aqui.

Descobri há muito, essa é uma discussão com mais de 10 anos na falta de um termo mais adequado: uma besteira de tão fácil,  algo relativamente simples e coerente que segue a semática geral:  "desalocação" de um ponteiro de vetor é um tipo vetor, de um ponteiro de int um int.

 

 

><

 

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

11 horas atrás, mauro_b disse:

Não acontecer nada significa que os comandos estão certos, o objetivo foi esse mesmo

 

É muito reconfortante saber que comandos que não fazem nada estão certos, imagino.

 

12 horas atrás, mauro_b disse:

Descobri há muito, essa é uma discussão com mais de 10 anos na falta de um termo mais adequado: uma besteira de tão fácil,  algo relativamente simples e coerente que segue a semática geral:  "desalocação" de um ponteiro de vetor é um tipo vetor, de um ponteiro de int um int

 

Imagino que pretendia escrever "semântica". 
 

Acho que sabe que ao citar isso cortado do texto que escrevi não dá pra entender do que eu estava falando... Vou mostrar de novo:
 

void test_3(int(*testt)[])
{
	printf("Vetor 'testt' entrando em test_3():\t%4i %4i %4i %4i Endereco de testt: %p\n",
		(*testt)[0], (*testt)[1], (*testt)[2], (*testt)[3],
		testt);
	(*testt)[0] = 1;
	(*testt)[3] = 2;

 

E foi por isso. E são mais de 10 anos. Já era assim em '80. E ninguém usa isso na prática. A menos que você o faça e tenha uns exemplos. Eu mostrei acho que 6 maneiras de fazer a mesma coisa. Essa é a menos útil. E eu mostrei essa e você não... Apenas deixou o "comando" como se fosse o recomendado e correto. Leia:
 

21 horas atrás, mauro_b disse:

demostra não entender corretamente que um PONTEIRO PARA VETOR DE INT tem esta nomenclatura int (*) [].

 

Sobre o programa que postou:
 

int main(void) {
	int y[] = {0, 2, 3, 4};

	printf("%i\n", y[0]);
	
	test(y);

	printf("%i", y[0]);
	return 0;
}
void test(int testt[]) {
	testt= (int []) {0, 2, 3, 4};
    testt[0] = 20;
}

 

Entenda que não está mudando nada. Talvez para mostrar que está funcionando você apenas colocou de novo os mesmos valores na função e em main(), talvez por preguiça, sei lá.

 

Ao mudar testt dentro da função está apenas desconectando a função do endereço do vetor dos argumentos. Como escreveu vai parecer igual, claro,  e talvez fosse sua intenção até :D mas é como se fosse um memory leak ao avesso: está perdendo contato com o array de argumentos que foi passado. Era o que eu tentava dizer por imutável. E não foi uma boa expressão de minha parte. 
 

Como você usou um novo valor declarado aí dentro ele vai morrer aí dentro. nada mais vai retornar dessa função. É muito difícil isso não ser apenas um erro ou uma bobagem.
 

Ao escrever em seu programa testt= (int []) {0, 2, 3, 4}; está desconectando a função definitivamente do mundo externo. Acho que usa C há mais de 10 anos --- é bastante tempo afinal --- como sugeriu deve perceber o que está fazendo: nada. Tudo que fizer aí dentro vai sumir, já que a função retorna void.

 

Veja uma implementação de test() usando essa ideia:
 

void test(int testt[])
{
	printf("Vetor 'testt' entrando em test():\t%4i %4i %4i %4i Endereco de testt: %p\n",
		testt[0], testt[1], testt[2], testt[3],
		testt);

	testt[0] = 20;
	testt[1] = 21;
	testt = (int[]){ -1, -2, -3, -4, -5, -6, -7, -8 };
	testt[2] = 22;
	testt[3] = 23;

	int outro = 2;
	testt = &outro;
	*testt = 2222;

	printf("Vetor 'testt' saindo   de test():\t\
%4i %4i %4i %4i %4i %4i %4i %4i\n",
		testt[0], testt[1], testt[2], testt[3],
		testt[4], testt[5], testt[6], testt[7]);
	printf("Endereco de testt: %p\n", testt);
}

 

Até a redefinição de testt  a função estava conectada com main(). A partir daí não mais. Veja o que muda na execução:

 

Agora:
 

y antes    1    2    3    4 Endereco de y: 00D3F940
z antes    5    6    7    8 Endereco de z: 00D3F928
chamando test() com vetor y
Vetor 'testt' entrando em test():          1    2    3    4 Endereco de testt: 00D3F940
Vetor 'testt' saindo   de test():       2222 -858993460 -858993460   -1   -2   22   23   -5
Endereco de testt: 00D3F800
y em main() depois de test()   20   21    3    4 Endereco de y: 00D3F940

chamando test() com vetor z
Vetor 'testt' entrando em test():          5    6    7    8 Endereco de testt: 00D3F928
Vetor 'testt' saindo   de test():       2222 -858993460 -858993460   -1   -2   22   23   -5
Endereco de testt: 00D3F800

y depois   20   21    3    4
z depois   20   21    7    8

 

Antes:
 

y antes    1    2    3    4 Endereco de y: 0136FCCC
z antes    5    6    7    8 Endereco de z: 0136FCB4

chamando test() com vetor y
Vetor 'testt' entrando em test():          1    2    3    4 Endereco de testt: 0136FCCC
Vetor 'testt' saindo   de test():         20   21   22   23
y em main() depois de test()   20   21   22   23 Endereco de y: 0136FCCC

chamando test() com vetor z
Vetor 'testt' entrando em test():          5    6    7    8 Endereco de testt: 0136FCB4
Vetor 'testt' saindo   de test():         20   21   22   23

y depois   20   21   22   23
z depois   20   21   22   23

 

Acho que entende a diferença: a função calcula e retorna algo. Até forçar a mudança de testt.

 

O seu programa mostrou dois valores iguais obtidos de main(), talvez apenas para mostrar que você está certo. E talvez terminar com "exit code 0" seja o suficiente para você achar que fez algo:

 

	printf("%i\n", y[0]);	
	test(y);
	printf("%i", y[0]);


No entanto se mudou o valor de y na função antes de usar, C fez sua parte e passou o endereço. Você não imprimiu, não usou e trocou por outro. Apenas isso. Redefiniu e também não mostrou então a função nada deixou para trás:
 

void test(int testt[])
{
	testt= (int []) {0, 2, 3, 4};
    testt[0] = 20;
}

 

image.png.e15f038df714db7e9796b72a3445fea1.png

 

Mas deu certo! Retornou 0.
 

Acrescentando os endereços no meu exemplo fica claro o que acontece internamente:

 

y antes    1    2    3    4 Endereco de y: 00D3F940
z antes    5    6    7    8 Endereco de z: 00D3F928

chamando test() com vetor y
Vetor 'testt' entrando em test():          1    2    3    4 Endereco de testt: 00D3F940
Vetor 'testt' saindo   de test():       2222 -858993460 -858993460   -1   -2   22   23   -5
Endereco de testt: 00D3F800
y em main() depois de test()   20   21    3    4 Endereco de y: 00D3F940

chamando test() com vetor z
Vetor 'testt' entrando em test():          5    6    7    8 Endereco de testt: 00D3F928
Vetor 'testt' saindo   de test():       2222 -858993460 -858993460   -1   -2   22   23   -5
Endereco de testt: 00D3F800

y depois   20   21    3    4
z depois   20   21    7    8

chamando test_2() (usando ponteiro) com vetor z
Vetor 'testt' entrando em test_2():       20   21    7    8 Endereco de testt: 00D3F928
Vetor 'testt' dentro  de  test_2():      -20  -19  -18  -17

 

Usei a versão que mostrei acima de test() e se pode ver claramente onde a função se desconectou do mundo externo: na redefinição de testt que quase sempre é um erro ou uma bobagem.

 

Note que o endereço de testt dentro da função começa preservado, claro. E depois é alterado. E veja que numa segunda chamada com outro vetor o endereço interno é restaurado, como se tivesse sido declarado static: 0xD3F800

 

Eu expliquei como passar por valor e por referência o vetor e mostrei uma meia dúzia de exemplos, inlcusive aquele que você apontou como trivial e bem conhecido. Você mostrou sua discordância e esses dois exemplos. Acho que está bem para o forum já!

 

Eis o meu programa de exemplo atualizado, que usa todas essas maneiras para passar um vetor como parâmetro, por valor ou por referência --- como em java, que passa todos os objetos e arrays por referência  --- e o resultado estará depois.

Spoiler

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

typedef struct
{
    int y[4];

}   Pacote;

void test(int testt[]);
void test_2(int* testt);
void test_3(int(*)[]);
void test_st(Pacote  pct);
void test_st2(Pacote* pct);

int main(void)
{
    int  y[] = { 1,2,3,4 };
    int  z[] = { 5,6,7,8 };

    printf("y antes %4i %4i %4i %4i Endereco de y: %p \n",
        y[0], y[1], y[2], y[3],
        y);
    printf("z antes %4i %4i %4i %4i Endereco de z: %p\n",
        z[0], z[1], z[2], z[3],
        z);

    printf("\nchamando test() com vetor y\n");
    test(y);
    printf("y em main() depois de test() %4i %4i %4i %4i Endereco de y: %p \n",
        y[0], y[1], y[2], y[3],
        y);

    printf("\nchamando test() com vetor z\n");
    test(z);

    printf("\ny depois %4i %4i %4i %4i\n", y[0], y[1], y[2], y[3]);
    printf("z depois %4i %4i %4i %4i\n", z[0], z[1], z[2], z[3]);

    // chamando usando o ponteiro
    printf("\nchamando test_2() (usando ponteiro) com vetor z\n");
    test_2(z);

    // chamando usando o ponteiro com int (*)[]
    printf("\nchamando test_3() (usando int (*)[]) com vetor z\n");
    printf("z antes %4i %4i %4i %4i Endereco de z: %p \n",
        z[0], z[1], z[2], z[3],
        z);
    test_3(&z);

    Pacote p;
    p.y[0] = 9;
    p.y[1] = 10;
    p.y[2] = 11;
    p.y[3] = 12;

    // passagem por valor

    printf("\nvetor 'p' na estrutura antes\t\
 %4i %4i %4i %4i. Endereco: %p\n",
        p.y[0], p.y[1], p.y[2], p.y[3],
        &p);
    test_st(p);
    printf("vetor na estrutura em main() no retorno\t\
 %4i %4i %4i %4i\n", p.y[0], p.y[1], p.y[2], p.y[3]);

    printf("\nPassando afinal a estrutura por referencia\n");
    test_st2(&p);
    printf("vetor na estrutura em main() no retorno\t\
 %4i %4i %4i %4i\n", p.y[0], p.y[1], p.y[2], p.y[3]);

    return 0;
}

void test(int testt[])
{
    printf("Vetor 'testt' entrando em test():\t%4i %4i %4i %4i Endereco de testt: %p\n",
        testt[0], testt[1], testt[2], testt[3],
        testt);

    testt[0] = 20;
    testt[1] = 21;
    //testt = (int[]){ -1, -2, -3, -4, -5, -6, -7, -8 };
    testt[2] = 22;
    testt[3] = 23;

    //int outro = 2;
    //testt = &outro;
    //*testt = 2222;
//    printf("Vetor 'testt' saindo   de test():\t\
//%4i %4i %4i %4i %4i %4i %4i %4i\n",
//testt[0], testt[1], testt[2], testt[3],
//testt[4], testt[5], testt[6], testt[7]);
//    printf("Endereco de testt: %p\n", testt);

    printf("Vetor 'testt' saindo   de test():\t\
%4i %4i %4i %4i\n",
testt[0], testt[1], testt[2], testt[3]);

}

void test_2(int* testt)
{
    printf("Vetor 'testt' entrando em test_2():\t%4i %4i %4i %4i Endereco de testt: %p\n",
        testt[0], testt[1], testt[2], testt[3],
        testt);
    testt[0] = -20;
    testt[1] = -19;
    testt[2] = -18;
    testt[3] = -17;
    int outro = 0;
    //testt = &outro; // aqui daria erro: testt nao pode apontar para outra coisa
    printf("Vetor 'testt' dentro  de  test_2():\t%4i %4i %4i %4i\n",
        testt[0], testt[1], testt[2], testt[3]);
}

void test_3(int(*testt)[])
{
    printf("Vetor 'testt' entrando em test_3():\t%4i %4i %4i %4i Endereco de testt: %p\n",
        (*testt)[0], (*testt)[1], (*testt)[2], (*testt)[3],
        testt);
    (*testt)[0] = 1;
    (*testt)[3] = 2;
    (*testt)[0] = 3;
    (*testt)[3] = 4;
    int outro = 0;
    //testt = &outro; // aqui daria erro: testt nao pode apontar para outra coisa
    printf("Vetor 'testt'  saindo  de test_3():\t%4i %4i %4i %4i Endereco de testt: %p\n",
        (*testt)[0],
        (*testt)[1],
        (*testt)[2],
        (*testt)[3],
        testt);
};

void test_st(Pacote pct)
{
    printf("(passagem por valor)\n\
vetor 'pct' entrando em test_st():\t\
 %4i %4i %4i %4i Endereco: %p\n",
        pct.y[0], pct.y[1],
        pct.y[2], pct.y[3],
        &pct);
    pct.y[0] = 15;
    pct.y[1] = 16;
    pct.y[2] = 17;
    pct.y[3] = 18;
    printf("\
vetor 'pct'  saindo de  test_st():\t\
 %4i %4i %4i %4i Endereco: %p\n",
        pct.y[0], pct.y[1],
        pct.y[2], pct.y[3],
        &pct);
};

void test_st2(Pacote* pct)
{
    printf("(passagem por referencia)\n\
vetor 'pct' entrando em test_st2():\t\
 %4i %4i %4i %4i Endereco: %p\n",
        pct->y[0], pct->y[1],
        pct->y[2], pct->y[3],
        pct);
    pct->y[0] = 40;
    pct->y[1] = 41;
    pct->y[2] = 42;
    pct->y[3] = 43;
    printf("\
vetor 'pct' entrando em test_st2():\t\
 %4i %4i %4i %4i\n",
        pct->y[0], pct->y[1],
        pct->y[2], pct->y[3]);
};

// fim

O resultado bem comportado e previsível seria esse:
 

y antes    1    2    3    4 Endereco de y: 0111FCE0
z antes    5    6    7    8 Endereco de z: 0111FCC8

chamando test() com vetor y
Vetor 'testt' entrando em test():          1    2    3    4 Endereco de testt: 0111FCE0
Vetor 'testt' saindo   de test():         20   21   22   23
y em main() depois de test()   20   21   22   23 Endereco de y: 0111FCE0

chamando test() com vetor z
Vetor 'testt' entrando em test():          5    6    7    8 Endereco de testt: 0111FCC8
Vetor 'testt' saindo   de test():         20   21   22   23

y depois   20   21   22   23
z depois   20   21   22   23

chamando test_2() (usando ponteiro) com vetor z
Vetor 'testt' entrando em test_2():       20   21   22   23 Endereco de testt: 0111FCC8
Vetor 'testt' dentro  de  test_2():      -20  -19  -18  -17

chamando test_3() (usando int (*)[]) com vetor z
z antes  -20  -19  -18  -17 Endereco de z: 0111FCC8
Vetor 'testt' entrando em test_3():      -20  -19  -18  -17 Endereco de testt: 0111FCC8
Vetor 'testt'  saindo  de test_3():        3  -19  -18    4 Endereco de testt: 0111FCC8

vetor 'p' na estrutura antes        9   10   11   12. Endereco: 0111FCB0
(passagem por valor)
vetor 'pct' entrando em test_st():          9   10   11   12 Endereco: 0111FBD0
vetor 'pct'  saindo de  test_st():         15   16   17   18 Endereco: 0111FBD0
vetor na estrutura em main() no retorno     9   10   11   12

Passando afinal a estrutura por referencia
(passagem por referencia)
vetor 'pct' entrando em test_st2():         9   10   11   12 Endereco: 0111FCB0
vetor 'pct' entrando em test_st2():        40   41   42   43
vetor na estrutura em main() no retorno    40   41   42   43

 

Mas alterando test() para incorporar sua ideía seria o que postei acima...

 

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

 

Em 15/10/2020 às 17:23, arfneto disse:

Ao escrever em seu programa testt= (int []) {0, 2, 3, 4}; está desconectando a função definitivamente do mundo externo. Acho que usa C há mais de 10 anos --- é bastante tempo afinal --- como sugeriu deve perceber o que está fazendo: nada. Tudo que fizer aí dentro vai sumir, já que a função retorna void.

 

Acredito que o objetivo é demostrar, por simples acesso, que o parâmetro da função quando citado na maneira que fora: é variável de ponteiro e não contaste.

 

Enfim,

O mais importante; A matriz (propriamente dita com os elementos e seus valores) não é copiada, porém, sim o endereço é copiado, mais precisamente, o do primeiro elemento.

 

 

 

Quadro de sugestão, sematicamente, certo. Legal!

int y[] = {0, 2, 3, 4}; test(int testt[]) --> test (int *testt)
                        |        ^----------> é só outro nome para int *testt
                        |
                        +--------> test(y): test (int *tesst= y)
                                                      ^-----= &(y[0])

   +-------+-------+-------+-------+
y  |   0   |   2   |   3   |   4   |
^  +-------+-------+-------+-------+
|     ^
|     |
+-----+---> 0x100407000
      |
      +------> &(y[0])= 0x100407000
             |
             +------> &(y[1])= 0x100407004
                      |
                      +------> &(y[2])= 0x100407008
                             |
                             +------> &(y[3])= 0x10040700c

 

 

E contribuições para o quadro serão bem-vindas,

outra coisa, é bom para discussão alguém deixa um glossário.

"

Link para o comentário
Compartilhar em outros sites

3 horas atrás, mauro_b disse:

E contribuições para o quadro serão bem-vindas

 

Eu postei acho que 5 versões de um programa completo, compilável e com o resultado da execução anexado. E o resultado inclui os valores dos ponteiros onde achei que faria sentido. E expliquei como passar um array por valor e por referência e as implicações disso, além do exemplo propriamente dito

 

3 horas atrás, mauro_b disse:

é bom para discussão alguém deixa um glossário

 

Que gostaria de ver no glossário? Posso acrescentar talvez.


De seus posts posso colocar algo:
 

3 horas atrás, mauro_b disse:

A matriz (propriamente dita com os elementos e seus valores) não é copiada, porém, sim o endereço é copiado, mais precisamente, o do primeiro elemento

 

Isso seria provavelmente uma descrição de passagem por referência

 

3 horas atrás, mauro_b disse:

contaste

 

Isso seria constante, creio

 

3 horas atrás, mauro_b disse:

sematicamente

 

Isso seria semanticamente, imagino
 

3 horas atrás, mauro_b disse:

demostrar


Isso seria demonstrar
 

3 horas atrás, mauro_b disse:

é variável de ponteiro


Isso não sei o que é. Poderia incluir no glossário uma outra definição?

 

Em 15/10/2020 às 04:34, mauro_b disse:

uma besteira de tão fácil,  algo relativamente simples e coerente que segue a semática geral:  "desalocação" de um ponteiro de vetor é um tipo vetor, de um ponteiro de int um int

 

Isso também não entendi. mas imagino que tenha a ver com semântica. Poderia incluir no glossário alguma outra definição?
 

 

🤔num forum para iniciantes como parece ser esse aqui não parece educado dizer que algo é "uma besteira de tão fácil"
 

Em 15/10/2020 às 04:34, mauro_b disse:

 A pastagem, no momento que trata de vetores considera

 

Estranhei a referência à "pastagem". Imagino que pretendia escrever "postagem". Em geral se espera uma vírgula depois de "vetores". Mas isso seria assunto para outro forum
 

Em 14/10/2020 às 19:33, mauro_b disse:

Eu pensei que um desenho seria mais acessível, me enganei, pelo visto é necessário mais que isso

 

Em 15/10/2020 às 04:34, mauro_b disse:

Estranho mesmo a sua pouca capacidade de interpretar, mas não é surpresa nenhuma, haja vista que se um desenho não é o bastante então não posso ajudar


Observações assim não parecem muito educadas para um forum público. Mas pode ser apenas um exagero de sensibilidade de minha parte.

"Passagem por valor"

 

Em 14/10/2020 às 09:33, mauro_b disse:

somente há passagem por valor. No caso especial dos ponteiros o valor é um endereço

 

Essa parte explica bem, segundo você, porque não existe passagem por referência: no caso dos ponteiros o valor é um endereço.

Endereço esse que se refere ao parâmetro. Mas não é uma referência. Apenas semântica. E as referencias em java a arrays e objetos também são isso. Se chamam references mas são apenas valores que por acaso se referem a alguma coisa. E declarar algo como int& em C++ também é um valor. Que por acaso se lê como referência a int, mas é um valor.

E um ponteiro também é um valor. 🤔. E declarar algo como var em Pascal também deve ser uma passagem por valor, apesar de ser uma referência. 
 

Imagino que seja isso que você estava tentando nos explicar nesse tópico.

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

 

 

3 horas atrás, arfneto disse:

🤔num forum para iniciantes como parece ser esse aqui não parece educado dizer que algo é "uma besteira de tão fácil"

Não mesmo, desculpas.

 

 

 

3 horas atrás, arfneto disse:

é variável de ponteiro

Isso não sei o que é. Poderia incluir no glossário uma outra definição?

É um ponteiro que não é declarado constante (ponteiro variável) ou local na memória reservada para o ponteiro.

"

 

Passagem por valor?

Tem-se a cópia do valor entre variáveis ao chamar uma função que permite usar dentro dela o valor da variável original (argumento) e somente a cópia pode ser modificada. Agora, depende do que é 'valor', pois é costume há anos dizer que quando as variáreis são ponteiros a passagem é por referência.
 

 

3 horas atrás, arfneto disse:

"Passagem por valor"

 

Em 14/10/2020 às 09:33, mauro_b disse:

somente há passagem por valor. No caso especial dos ponteiros o valor é um endereço

 

Essa parte explica bem, segundo você, porque não existe passagem por referência: no caso dos ponteiros o valor é um endereço.

Endereço esse que se refere ao parâmetro. Mas não é uma referência. Apenas semântica. E as referencias em java a arrays e objetos também são isso. Se chamam references mas são apenas valores que por acaso se referem a alguma coisa. E declarar algo como int& em C++ também é um valor. Que por acaso se lê como referência a int, mas é um valor.

E um ponteiro também é um valor. 🤔. E declarar algo como var em Pascal também deve ser uma passagem por valor, apesar de ser uma referência. 
 

Imagino que seja isso que você estava tentando nos explicar nesse tópico.

 

C++ tem sim um dado da "família" dos ponteiros com este nome: 'Reference'.

 

É um ponteiro mais seguro que não permite as operações comuns de ponteiros. Por exemplo. Depois que a Reference é criada ela não pode ser modificada.

 

C não tem esse dado, somente ponteiro (outro tipo referência) são alegorias das referências que existem em C++.

Sejam ponteiros ou references (C++) é tudo dado referência, são variáveis cujo valor é um endereço de outra.

 

Um parâmetro de função que é escrito com a mesma nomenclatura que autor do tópico escreve, não cria uma references, ou ponteiro constante: que o mais próximo da reference (C++), mas sim um ponteiro variável sem restrições. 

"

 

Quadro de sugestão, semanticamente, certo. Legal!

int y[] = {0, 2, 3, 4}; test(int testt[]) --> test (int *testt)
                        |        ^----------> é só outro nome para int *testt
                        |
                        +--------> test(y): test (int *tesst= 0x100407000)
                                                      ^-----= &(y[0])

   +-------+-------+-------+-------+
y  |   0   |   2   |   3   |   4   |
^  +-------+-------+-------+-------+
|     ^
|     |
+-----+---> 0x100407000
      |
      +------> &(y[0])= 0x100407000
             |
             +------> &(y[1])= 0x100407004
                      |
                      +------> &(y[2])= 0x100407008
                             |
                             +------> &(y[3])= 0x10040700c

"

 

E contribuições para o quadro serão bem-vindas,

outra coisa, é bom para discussão alguém deixa um glossário.

"

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!