Enviado em 28/01/2022 - 16:13h
Boa Tarde a TodosEnviado em 29/01/2022 - 22:16h
const char *Nome="Viva o Linux";
int *pi; // Um ponteiro para dado cujo tipo é int (abreviadamente: ponteiro para int).
char *pc; // Um ponteiro para dado cujo tipo é char (abreviadamente: ponteiro para char).
const char *my_argv[25]; // Um array com 25 elementos que são ponteiros para dados que são do tipo caráter constante (abreviadamente: array com 25 ponteiros para const char).
double (*pv)[3]; // Um ponteiro para dado que é tipo array com 3 elementos do tipo double (abreviadamente: ponteiro para array (com 3 elementos) de double).
&c /* Se c tiver sido declarado com o tipo char, produz um ponteiro com o endereço de c e o tipo de dado associado char. */
&i /* Se i tiver sido declarado com o tipo int, produz um ponteiro com o endereço de i e o tipo de dado associado int. */
some_array /* Se some_array tiver sido declarado como array para elementos de um determinado tipo, produz o endereço do primeiro elemento e o tipo de dado associado é o mesmo tipo de cada elemento do array. */
(long *)12345678900 /* Ponteiro para dado do tipo long int residente no endereço de memória 12345678900. */
NULL /* Essa constante geralmente é definida em C (em <stddef.h>) como “(void *)0” (“void *” é algo como “ponteiro para qualquer coisa”: você terá de converter para outra coisa antes de poder usar; também pode ser considerado “ponteiro para dado de tipo indefinido”). */
(void *)addr /* Se addr tiver sido declarado com um tipo de dados inteiro, converte esse valor para um endereço para dado de tipo indefinido. */
sbrk(0) /* Chama uma função (declarada em sistemas UNIX-like em <unistd.h>) que aloca memória e retorna o ponteiro para o fim da região de memória alocada (no caso, aloca 0 bytes, retornando apenas o fim da área de dados). O tipo do dado retornado é void *. */
// Caso 1: sucessão de valores independentes no tempo: OK.
int main(void){
const char *Nome;
Nome="Viva o Linux"; // Aponta para uma constante literal string.
/* ... */
Nome="Viva o Linux no Brasil"; // Aponta para outra constante literal string em outro momento, posterior.
/* ... */
}
// Caso 2: alteração de conteúdo de constante literal string: ERRO JÁ EM TEMPO DE COMPILAÇÃO.
int main(void){
const char *Nome; // O fato de ter o const já deve servir de alerta...
Nome="Viva o Linux"; // Aponta para uma constante literal string.
strcat(Nome, " no Brasil"); // O compilador vai dar erro, porque o primeiro argumento não pode ser do tipo const char *.
}
// Caso 3: abusando da anomalia no sistema de tipos: ERRO EM TEMPO DE EXECUÇÃO.
int main(void){
char *Nome;
Nome="Viva o Linux"; // Aponta para uma constante literal string usando um ponteiro para dados não-constantes: PROBLEMA, mas permitido em C (inválido em C++).
strcat(Nome, " no Brasil"); // PROBLEMA: o compilador vai deixar passar, porque os tipos dos argumentos são compatíveis, mas o primeiro argumento aponta para memória que não pode ser modificada; o programa provavelmente vai capotar com SIGSEGV.
}
// Caso 4: Usando vetor de caracteres com tamanho suficiente em vez de constante literal para a string: OK.
int main(void){
char Nome[40]="Viva o Linux"; // Coloca a string dentro de um array, que reside em região de memória que pode ser alterada.
strcat(Nome, " no Brasil"); // Lembrando que o nome de um array sozinho numa expressão se torna um ponteiro para o primeiro elemento, o array apontado tem espaço de sobra para acomodar os caracteres adicionais.
}
// Caso 5: Usando vetor de caracteres com tamanho limitado em vez de constante literal para a string: ERRO EM TEMPO DE EXECUÇÃO.
int main(void){
char Nome[]="Viva o Linux"; // Coloca a string dentro de um array, que reside em região de memória que pode ser alterada, mas que tem o espaço limitado apenas ao conteúdo original.
strcat(Nome, " no Brasil"); // O compilador deixa passar porque os tipos dos argumentos estão certos, mas a função strcat() não considera o tamanho reservado para o destino, então a concatenação é feita em uma memória que já não pertence ao array, com resultado imprevisível (mas seguramente errôneo!).
}
Enviado em 30/01/2022 - 00:28h
const char *Nome="Viva o Linux";
// Caso 1: sucessão de valores independentes no tempo: OK.
int main(void){
const char *Nome;
Nome="Viva o Linux"; // Aponta para uma constante literal string.
/* ... */
Nome="Viva o Linux no Brasil"; // Aponta para outra constante literal string em outro momento, posterior.
/* ... */
}
const char *text;
text = "1";
text = "2345"; // Neste caso o 1 acima, foi liberado da memória? Ou continua ocupando espaço? | Entendi que aqui 2345 está alocado corretamente com seu espaço necessário em um NOVO endereço de memória certo?
char Text[] = "Linux-Text"; // Então char Text[] seu valor é imutável usando um ponteiro certo? Visto que ponteiros não modificam valores, apenas apontam para valores existentes ou novos valores certo?
const char *Pointer = Text; // Entendi que Aponto Pointer para Text, assim Pointer passa a informar o valor de Text
Pointer = "Amor"; // Achei que mudaria o valor de Text! Mas pelas explicações acima, entendi que "Amor" foi alocado em um novo espaço de memória! Certo?
#include <stdio.h> // printf
#include <stdlib.h> // free
int main(void) {
const char *TextPtr = "Linux-Ptr";
const char *TextPtr2 = TextPtr;
// Esse Resultado está correto?
for( ; *TextPtr2 != '\0'; TextPtr2++)
printf("%p TextPtr[%ld] %c\toffset of TextPtr2[%ld] %p\t(TextPtr2 - TextPtr) = %ld\n", TextPtr, TextPtr2 - TextPtr, *TextPtr2, TextPtr2 - TextPtr, TextPtr2, TextPtr2 - TextPtr);
// Porque não funciona free pra esses Ponteiros?
// Caso não coloque como const: error: attempt to free a non-heap object
//free(TextPtr); // error: passing argument 1 of ‘free’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
//free(TextPtr2);
return 0;
}
/* RESULT
0x402004 TextPtr[0] L offset of TextPtr2[0] 0x402004 (TextPtr2 - TextPtr) = 0
0x402004 TextPtr[1] i offset of TextPtr2[1] 0x402005 (TextPtr2 - TextPtr) = 1
0x402004 TextPtr[2] n offset of TextPtr2[2] 0x402006 (TextPtr2 - TextPtr) = 2
0x402004 TextPtr[3] u offset of TextPtr2[3] 0x402007 (TextPtr2 - TextPtr) = 3
0x402004 TextPtr[4] x offset of TextPtr2[4] 0x402008 (TextPtr2 - TextPtr) = 4
0x402004 TextPtr[5] - offset of TextPtr2[5] 0x402009 (TextPtr2 - TextPtr) = 5
0x402004 TextPtr[6] P offset of TextPtr2[6] 0x40200a (TextPtr2 - TextPtr) = 6
0x402004 TextPtr[7] t offset of TextPtr2[7] 0x40200b (TextPtr2 - TextPtr) = 7
0x402004 TextPtr[8] r offset of TextPtr2[8] 0x40200c (TextPtr2 - TextPtr) = 8
*/
Enviado em 30/01/2022 - 01:09h
Um outro ponto que gostaria de entender é: Se eu posso então usar um ponteiro pra receber valores que não faço idéia do tamanho, tipo um texto inteiro de um arquivo que não sei qts caracteres terá! Uma idéia Ex abaixo!const char *Ptr = "Mini Text";
Ptr = "Texto muito Maior que o Mini Text";
Ptr = "Imagine aqui um Texto com 100.000 Caracteres";
Ptr = "Imagine aqui um Texto com 500.000 Caracteres";
Ptr = NULL; // Meu Computador liberou da memória os 500.000 Caracteres?
free(Ptr); // Meu Computador liberou da memória os 500.000 Caracteres?
Enviado em 30/01/2022 - 22:01h
const char *text;
text = "1";
text = "2345"; // Neste caso o 1 acima, foi liberado da memória? Ou continua ocupando espaço? | Entendi que aqui 2345 está alocado corretamente com seu espaço necessário em um NOVO endereço de memória certo?
char Text[] = "Linux-Text"; // Então char Text[] seu valor é imutável usando um ponteiro certo? Visto que ponteiros não modificam valores, apenas apontam para valores existentes ou novos valores certo?
const char Text[]="Texto-fixo";
const char *Pointer = Text; // Entendi que Aponto Pointer para Text, assim Pointer passa a informar o valor de Text
Pointer = "Amor"; // Achei que mudaria o valor de Text! Mas pelas explicações acima, entendi que "Amor" foi alocado em um novo espaço de memória! Certo?
#include <stdio.h> // printf
#include <stdlib.h> // free
int main(void) {
const char *TextPtr = "Linux-Ptr";
const char *TextPtr2 = TextPtr;
// Esse Resultado está correto?
for( ; *TextPtr2 != '\0'; TextPtr2++)
printf("%p TextPtr[%ld] %c\toffset of TextPtr2[%ld] %p\t(TextPtr2 - TextPtr) = %ld\n", TextPtr, TextPtr2 - TextPtr, *TextPtr2, TextPtr2 - TextPtr, TextPtr2, TextPtr2 - TextPtr);
Expressão Informação Conversão em printf
--------------------------------------------------------------------------------------
TextPtr Endereço inicial da string %p
TextPtr2 Endereço do ponteiro que percorre a string %p
*TextPtr2 Conteúdo do ponteiro que percorre a string %c
TextPtr2-TextPtr Deslocamento em relação ao início da string %td
TextPtr[ Valor do elemento correspondente ao deslo- %c
TextPtr2-TextPtr camento em relação ao início da string (=
] ao conteúdo do ponteiro que a percorre)
// Porque não funciona free pra esses Ponteiros?
// Caso não coloque como const: error: attempt to free a non-heap object
//free(TextPtr); // error: passing argument 1 of ‘free’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
//free(TextPtr2);
return 0;
}
/* RESULT
0x402004 TextPtr[0] L offset of TextPtr2[0] 0x402004 (TextPtr2 - TextPtr) = 0
0x402004 TextPtr[1] i offset of TextPtr2[1] 0x402005 (TextPtr2 - TextPtr) = 1
0x402004 TextPtr[2] n offset of TextPtr2[2] 0x402006 (TextPtr2 - TextPtr) = 2
0x402004 TextPtr[3] u offset of TextPtr2[3] 0x402007 (TextPtr2 - TextPtr) = 3
0x402004 TextPtr[4] x offset of TextPtr2[4] 0x402008 (TextPtr2 - TextPtr) = 4
0x402004 TextPtr[5] - offset of TextPtr2[5] 0x402009 (TextPtr2 - TextPtr) = 5
0x402004 TextPtr[6] P offset of TextPtr2[6] 0x40200a (TextPtr2 - TextPtr) = 6
0x402004 TextPtr[7] t offset of TextPtr2[7] 0x40200b (TextPtr2 - TextPtr) = 7
0x402004 TextPtr[8] r offset of TextPtr2[8] 0x40200c (TextPtr2 - TextPtr) = 8
*/
Enviado em 30/01/2022 - 22:34h
const char *Ptr = "Mini Text";
Ptr = "Texto muito Maior que o Mini Text";
Ptr = "Imagine aqui um Texto com 100.000 Caracteres";
Ptr = "Imagine aqui um Texto com 500.000 Caracteres";
Ptr = NULL; // Meu Computador liberou da memória os 500.000 Caracteres?
free(Ptr); // Meu Computador liberou da memória os 500.000 Caracteres?
Enviado em 31/01/2022 - 16:43h
const char *Nome="Viva o Linux";
const int *Numbers[] = { 3, 0, 1, 8, 7, 2, 5, 4, 9, 6 }; // Constante pq declarei como um ponteiro. Certo?
const *int Number = 10; // Constante pq declarei como um ponteiro. Certo?
const char *Nome; // Constante pq declarei como um ponteiro. Certo?
void funcao(int vector[]) // Melhor assimSe bem que acho que esse assunto de função trata-se de outro assunto diferente. Eu tenho que entender melhor ainda ponteiros pra entrar nesse outro campo de ponteiros com função, até porque ainda estou montando funções e entendendo como cada item nelas nelas funcionam.
void funcao(int *vector) // Do que assim?
char Text[] = "Linux-Text"; // Então char Text[] seu valor é imutável usando um ponteiro certo? Visto que ponteiros não modificam valores, apenas apontam para valores existentes ou novos valores certo?
char Text[] = "Linux-Text";O que eu quis dizer é que um ponteiro NUNCA vai conseguir mudar o valor de Text. Ou seja, não existe uma operação que permita um ponteiro mudar os dados atribuidos a uma variável, certo?
const char *Ponteiro;
Ponteiro = Text; // Ponteiro aponta para o Valor em Text
Enviado em 03/02/2022 - 22:44h
int *pi; // Ponteiro (não-constante) para dado inteiro (não-constante).
const int *pci; // Ponteiro (não-constante) para dado inteiro constante.
int const *pci2; // Outra forma de fazer ponteiro (não-constante) para dado inteiro constante (i.e. “int const” é sinônimo de “const int”).
typedef unsigned char byte;
// Com ponteiros constantes, convém definir seu valor (para onde aponta) no momento da declaração, pois depois não será possível alterá-lo.
byte *const cp_video_mem=(byte *)0x000b8000; // Ponteiro constante para (região de) dados do tipo byte (não-constantes) (0x000b8000 até 0x000bffff é a região de memória de vídeo para texto e modos gráficos de baixa resolução). Posso ler e alterar o conteúdo da memória de vídeo, pois apesar de o ponteiro ser constante, o dado apontado não o é.
const byte *const cp_mb_bios=(byte *)0x000f0000; // Ponteiro constante para (região de) dados constantes do tipo byte (0x000f0000 até 0x000fffff é (era) a região do BIOS da placa-mãe). Posso usar cp_mb_bios para examinar o conteúdo do BIOS, mas não para modificá-lo, porque aqui eu disse que os dados são constantes.
const int *Numbers[] = { 3, 0, 1, 8, 7, 2, 5, 4, 9, 6 }; // Constante pq declarei como um ponteiro. Certo?
const *int Number = 10; // Constante pq declarei como um ponteiro. Certo?
const char *Nome; // Constante pq declarei como um ponteiro. Certo?
/* 01 */ #include <stdio.h>
/* 02 */
/* 03 */ const char vowels[]={'a', 'e', 'i', 'o', 'u'}; // Array de 5 elementos explicitamente definidos como constantes (e que não é string, porque falta o byte nulo).
/* 04 */ char *p1=vowels; // Tipo de ponteiro incompatível com objeto apontado (ponteiro que permite acesso de modificação do dado, mas objeto apontado é constante).
/* 05 */ // Dependendo das opções de compilação, esse tipo incompatível pode ser considerada como erro (interrompendo a compilação), ou pode ser
/* 06 */ // apenas exibido um alerta de incompatibilidade, e a compilação pode prosseguir. Recomendo sempre parar a compilação nesses casos.
/* 07 */
/* 08 */ const char vowels_str[]="aeiou"; // Array de 6 elementos constantes (tanto os cinco do texto quanto o byte nulo).
/* 09 */ char *p2=vowels_str; // Tipo de ponteiro incompatível com objeto apontado. Mesmos comentários feitos sobre p1, acima, aplicam-se aqui.
/* 10 */
/* 11 */ const char vowels_str2[]="aeiou"; // Outro array, distinto do primeiro, embora o conteúdo seja idêntico ao daquele, de 6 elementos constantes.
/* 12 */
/* 13 */ // NOTA (e corolário para guardar): Arrays explicitamente declarados como tais ocupam regiões de memória distintas de outros arrays.
/* 14 */
/* 15 */ char *p3="aeiou"; // Constante literal produz array anônimo com seis elementos constantes, distinto de todos os arrays acima. A atribuição array de elementos
/* 16 */ // constantres ao ponteiro para dado não-constante é válida em C, porém perigosa.
/* 17 */ const char *p4="aeiou"; // O compilador pode (e normalmente vai) reaproveitar o mesmo array anônimo para essas duas constantes literais idênticas, de modo que
/* 18 */ // p3 e p4 podem apontar para o mesmo array anônimo (mesmo valor de ponteiro em duas variáveis ponteiro diferentes).
/* 19 */
/* 20 */ // Todos os arrays acima são tipicamente dispostos numa região de memória que tem o atributo de somente leitura (read-only): os
/* 21 */ // explicitamente declarados porque usaram o atributo const para seus elementos, e os decorrentes das constantes literais string
/* 22 */ // porque — oh! surpresa! — são literalmente constantes. É por esse motivo que não é seguro usar um ponteiro que não especifica
/* 23 */ // que seus dados são constantes para referir-se a algo que é constante: alguém (incluindo o compilador) poderia achar que o fato
/* 24 */ // de o ponteiro não restringir a modificação do dado apontado implica que o dado necessariamente pode ser modificado.
/* 25 */
/* 26 */ char some_chars[]="aeiou"; // Array com elementos que não são constantes. Os elementos serão dispostos numa região de memória específica para este novo array e, ao
/* 27 */ // contrário dos arrays acima, será colocado numa região de memória que não tem o atributo de apenas leitura.
/* 28 */ char *p5=some_chars; // Aponto com um ponteiro que permite acesso indireto de modificação, o que é OK, neste caso, pois o dado apontado realmente é modificável.
/* 29 */ const char *p6=some_chars; // Aponto com um ponteiro que permite acesso indireto de consulta, mas não de modificação. Isso também é OK: o atributo const, aplicado ao
/* 30 */ // dado apontado, não especifica a natureza do dado apontado, mas sim de que modo o ponteiro pode ser usado para obter acesso ao conteúdo.
/* 31 */
/* 32 */ const char *f(void){
/* 33 */ static const char static_vowels[]="aeiou"; // Dados locais estáticos, assim como variáveis globais, têm seus valores dispostos em memória durante a compilação, e não redefinidos cada
/* 34 */ static char static_chars[]="aeiou"; // vez que a função é invocada (são “locais” apenas no sentido de seu escopo de visibilidade, não em termos de tempo ou fluxo de vida).
/* 35 */
/* 36 */ const char local_vowels[]="aeiou"; // Dados locais automáticos (não-estáticos) têm seus valores iniciais atribuídos cada vez que a função é invocada. Nestas duas linhas,
/* 37 */ char local_chars[]="aeiou"; // “"abcde"” é uma constante literal string, que pode produzir um array anônimo com elementos constantes (podendo até ser o mesmo array anônimo
/* 38 */ // gerado na linha 15 e reaproveitado na linha 17), e esses elementos são copiados para os arrays locais automáticos cada vez que o fluxo
/* 39 */ // de execução passa pelas linhas 36 e 37. A memória de dados automáticos normalmente não possui o atributo de somente leitura, o que
/* 40 */ // significa que garantir que o atributo const na linha 34 será honrado por todos os ponteiros que vierem a apontar para o objeto será
/* 41 */ // responsabilidade exclusivamente do compilador (mas é bom o programador ajudar, não tentando abusar do sistema de tipos).
/* 42 */
/* 43 */ char *lp1=static_vowels; // ERRO/ALERTA: Tipo de ponteiro incompatível com objeto apontado (ponteiro sugere que dado pode ser modificado, mas objeto apontado é constante).
/* 44 */ char *lp2=static_chars; // OK: ponteiro que permite acesso de modificação apontando para dado modificável.
/* 45 */ char *lp3=local_vowels; // ERRO/ALERTA: Tipo de ponteiro incompatível com objeto apontado (ponteiro sugere que dado pode ser modificado, mas objeto apontado é constante).
/* 46 */ char *lp4=local_chars; // OK: ponteiro que permite acesso de modificação apontando para dado modificável.
/* 47 */
/* 48 */ const char *lp5=static_vowels; // OK: ponteiro que não permite acesso de modificação apontando para dado que não permite modificação.
/* 49 */ const char *lp6=static_chars; // OK: ponteiro que não permite acesso de modificação apontando para dado que permite modificação.
/* 50 */ const char *lp7=local_vowels; // OK: ponteiro que não permite acesso de modificação apontando para dado que não permite modificação.
/* 51 */ const char *lp8=local_chars; // OK: ponteiro que não permite acesso de modificação apontando para dado que permite modificação.
/* 52 */
/* 53 */ printf("%s, %s, %s, %s\n", lp1, lp2, lp3, lp4);
/* 54 */
/* 55 */ ++*lp1; // Provavelmente isto aqui vai fazer o programa capotar com falha de segmentação (SIGSEGV) — o ponteiro permite o acesso de modificação, mas o
/* 56 */ // dado apontado reside numa região de memória marcada com acesso somente de leitura.
/* 57 */ ++*lp2; // OK.
/* 58 */ ++*lp3; // Comportamento indeterminado (se a compilação não tiver parado na linha 45 por causa do erro de incompatibilidade de tipos, pode ser que a
/* 59 */ // CPU não tenha como verificar, em tempo de execução, que este array disposto na memória de dados automáticos não deveria ser modificado).
/* 60 */ ++*lp4; // OK.
/* 61 */ //++*lp5; ++*lp6; ++*lp7; ++*lp8; // Linha comentada porque o compilador não vai permitir nenhuma dessas operações que tentam usar um ponteiro para dado constante para modificar
/* 62 */ // o dado apontado (e isso ocorre mesmo que você não use a opção de compilação que transforma alertas em erros).
/* 63 */
/* 64 */ printf("%s, %s, %s, %s\n", lp5, lp6, lp7, lp8);
/* 65 */
/* 66 */ return lp2;
/* 67 */ }
/* 68 */
/* 69 */ int main(void){
/* 70 */ printf("vowels: addr=%p, size=%zu, contents=\"%.5s\"; p1: addr=%p, value=%p, contents=\"%.5s\"\n", vowels, sizeof vowels, vowels, &p1, p1, p1);
/* 71 */ ++*p1;
/* 72 */ printf("vowels: addr=%p, size=%zu, contents=\"%.5s\"; p1: addr=%p, value=%p, contents=\"%.5s\"\n\n", vowels, sizeof vowels, vowels, &p1, p1, p1);
/* 73 */
/* 74 */ printf("vowels_str: addr=%p, size=%zu, contents=\"%s\"; p2: addr=%p, value=%p, contents=\"%s\"\n", vowels_str, sizeof vowels_str, vowels_str, &p2, p2, p2);
/* 75 */ ++*p2;
/* 76 */ printf("vowels_str: addr=%p, size=%zu, contents=\"%s\"; p2: addr=%p, value=%p, contents=\"%s\"\n\n", vowels_str, sizeof vowels_str, vowels_str, &p2, p2, p2);
/* 77 */
/* 78 */ printf("vowels_str2: addr=%p, size=%zu, contents=\"%s\"\n\n", vowels_str2, sizeof vowels_str2, vowels_str2);
/* 79 */
/* 80 */ printf("p3: addr=%p, value=%p, contents=\"%s\"; p4: addr=%p, value=%p, contents=\"%s\"\n", &p3, p3, p3, &p4, p4, p4);
/* 81 */ ++*p3;
/* 82 */ printf("p3: addr=%p, value=%p, contents=\"%s\"; p4: addr=%p, value=%p, contents=\"%s\"\n\n", &p3, p3, p3, &p4, p4, p4);
/* 83 */
/* 84 */ printf("some_chars: addr=%p, size=%zu, contents=\"%s\"; p5: addr=%p, value=%p, contents=\"%s\"; p6: addr=%p, value=%p, contents=\"%s\"\n", some_chars, sizeof some_chars, some_chars, &p5, p5, p5, &p6, p6, p6);
/* 85 */ ++*p5;
/* 86 */ printf("some_chars: addr=%p, size=%zu, contents=\"%s\"; p5: addr=%p, value=%p, contents=\"%s\"; p6: addr=%p, value=%p, contents=\"%s\"\n\n", some_chars, sizeof some_chars, some_chars, &p5, p5, p5, &p6, p6, p6);
/* 87 */
/* 88 */ printf("%s\n", f());
/* 89 */ printf("%s\n", f());
/* 90 */ }
/*
As linhas 04, 09, 43 e 45 produzem mensagens de alerta (ou erro — eu recomendo usar as opções que fazem com que dê erro!).
Sem forçar a compilação sem que os abusos provoquem erro, mas apenas alertas, memso assim, as linhas 55, 71, 75 e 81 têm de
ser comentadas. Caso contrário, o programa vai capotar.
A linha 50 representa uma violação que fica latente, embora seja semanticamente parecida com a da linha 48, mas o programa
não capota na linha 58, como o faz na linha 55 se não estiver comentada, porque o hardware do PC não consegue marcar a memória
automática onde local_vowels é colocada como read-only.
A saída do programa, quando compilado ingorando os alertas e comentando as linhas indicadas acima, está abaixo. Note como,
ao se chamar f(), uma das strings que é declarada como constante (local_vowels) acaba sendo alterada por conta de um ponteiro
para dados não constantes para apontar para ela.
vowels: addr=0x5621b350abe8, size=5, contents="aeiou"; p1: addr=0x5621b370c020, value=0x5621b350abe8, contents="aeiou"
vowels: addr=0x5621b350abe8, size=5, contents="aeiou"; p1: addr=0x5621b370c020, value=0x5621b350abe8, contents="aeiou"
vowels_str: addr=0x5621b350abed, size=6, contents="aeiou"; p2: addr=0x5621b370c028, value=0x5621b350abed, contents="aeiou"
vowels_str: addr=0x5621b350abed, size=6, contents="aeiou"; p2: addr=0x5621b370c028, value=0x5621b350abed, contents="aeiou"
vowels_str2: addr=0x5621b350abf3, size=6, contents="aeiou"
p3: addr=0x5621b370c030, value=0x5621b350abf9, contents="aeiou"; p4: addr=0x5621b370c038, value=0x5621b350abf9, contents="aeiou"
p3: addr=0x5621b370c030, value=0x5621b350abf9, contents="aeiou"; p4: addr=0x5621b370c038, value=0x5621b350abf9, contents="aeiou"
some_chars: addr=0x5621b370c010, size=6, contents="aeiou"; p5: addr=0x5621b370c040, value=0x5621b370c010, contents="aeiou"; p6: addr=0x5621b370c048, value=0x5621b370c010, contents="aeiou"
some_chars: addr=0x5621b370c010, size=6, contents="beiou"; p5: addr=0x5621b370c040, value=0x5621b370c010, contents="beiou"; p6: addr=0x5621b370c048, value=0x5621b370c010, contents="beiou"
aeiou, aeiou, aeiou, aeiou
aeiou, beiou, beiou, beiou
beiou
aeiou, beiou, aeiou, aeiou
aeiou, ceiou, beiou, beiou
ceiou
*/
char some_chars[]="abcde";
const char vowels[]="aeiou";
void f(void){
// Todas as atribuições dos ponteiros abixo são válidas.
char *const p1=some_chars;
char *p2=some_chars;
const char *p3=some_chars;
const char *const p4=some_chars;
++some_chars; // ERRO: neste contexto, some_chars decai para um ponteiro constante para o primeiro elemento; sendo constante, não pode ser alterado.
++*some_chars; // OK: posso alterar o elemento referido pelo ponteiro constante, pois o tipo do elemento não é constante.
++p1; // ERRO: o ponteiro é constante, logo não pode ser alterado.
++*p1; // OK: dado apontado não é constante.
++p2; // OK: ponteiro não-constante passa a apontar para o segundo elemento do array.
++*p2; // OK: altera o segundo elemento do array (dado apontado não é constante).
++p3; // OK: ponteiro não-constante passa a apontar para o segundo elemento do array.
++*p3; // ERRO: dado apontado é inidicado como constante, logo não pode ser alterado.
++p4; // ERRO: o ponteiro é constante, logo não pode ser alterado.
++*p4; // ERRO: o dado apontado é indicado como constante, logo não pode ser alterado.
}
void g(void){
// Não vou nem tentar usar ponteiros para dados não-constantes, que seria uma violação de tipo (ver programa exemplo mostrado no exemplo anterior).
const char *p1=vowels;
const char *const p2=vowels;
++vowels; // ERRO: Neste contexto, vowels decais para um ponteiro constante para o primeiro elemento; sendo constante, não pode ser alterado.
++*vowels; // ERRO: não posso alterar o elemento referido pelo ponteiro constante porque o tipo do elemento também é constante.
++p1; // OK: ponteiro não-constante passa a apontar para o segundo elemento do array.
++*p1; // ERRO: dado apontado é indicado como constante, logo não pode ser alterado.
++p2; // ERRO: o ponteiro é constante, logo não pode ser alterado.
++*p2; // ERRO: dado apontado é indicado como constante, logo não pode ser alterado.
}
void funcao(int vector[]) // Melhor assim
void funcao(int *vector) // Do que assim?
Subindo o Zabbix e Grafana no Podman com Pod
Habilitar a aceleração por hardware AMD AMF no OBS
Roubando bits (parte 2): como resolver questões rapidamente sem calculadora
Usando Linux para operar plataformas de análise gráfica na Bovespa (B3)
Instalando Google Chrome no Ubuntu 22.04 LTS
Bodhi Linux: melhor distro Linux para Atom N455
Solução Touchpad Notebook Lenovo S145
Dificuldade para logar no VOL (34)
Frustrando o que não existe pra ser frustrado. (0)
Entrada de argumento ao executar shell script. [RESOLVIDO] (3)