Tristeza com Ponteiros em C++ [RESOLVIDO]

1. Tristeza com Ponteiros em C++ [RESOLVIDO]

Nick Us
Nick-us

(usa Slackware)

Enviado em 10/05/2020 - 13:20h

Neste momento fiquei mesmo desanimado! Eu ainda estou aprendendo C e falta um Mundo de coisas para eu entender! Acontece que estou fazendo um programinha usando a wxWidgets que é C++. E por mais que eu me esforce pra escrever em C tudo o que eu posso, começo a perceber que o compilador não me compreende e desconfio severamente que ele está tratando o meu código como C++ em todos os casos!

Montei um exemplo bonito de um ponteiro usando um vetor de char, salvei para que eu use como consulta, para usar qdo fosse precisar, então hoje qdo coloquei no meu código em C++ o compilador reclama me importuna e nem obedece as regras que eu havia com tanta dificuldade em aprender!

Aprendi com Paulo aqui no Fórum a compilar com TODOS os avisos ao máximo ligado, demorei pra entender isso, agora que entendi achei o máximo, venho resolvendo inúmeras reclamações do compilador e com dificuldades em cada uma delas, mas o compilador não tem nenhum respeito, parece uma perseguição!

CASO: O Exemplo abaixo aprendi na Internet, uma forma de passar valores de um ponteiro pro outro, e eu usaria isso para tratar a String recebida podendo modificá-la e etc... Isso abaixo funciona perfeitamente em C
      while(*pA != '\0') // Repete o while até encontrar em pA o fim de string
*pB++ = *pA++; // pB recebe pA e se Incrementam
*pB = '\0';

Tentei fazer algo similar em C++ e o compilador tá estragando tudo! Ele não aceita uma simples declaração como:
char *Nome = "Nick"; 

Apanhei muito pra resolver isso, e o compilador não fica satisfeito! Eu preciso fazer isso funcionar
*pB++ = *pA++;  

Mas não tenho a mínima idéia de como fazer isso! Gastei dias e nada! Abaixo vou mostrar o trecho do código em C++ que estou tentando fazer funcionar e explicarei porque! Ele já ficou uma ZONA de tanta coisa que comentei, modifiquei gerando muito mais confusão pra mim!
// FAZENDO ➤ Ler a Linha 3 do arquivo para EdGroups. Sendo que a cada Campo Lido preciso alimentar ChGroup (10/05/2020 12:05)

MyFile = fopen(Path, "r");
size_t Line_Size; // Posso também chutar um valor para Line_Size que seria o Tamanho da linha, pois getline calcula automaticamente pra mim se eu errar, aqui informei vazio né.
char *Line_Content;

// Tenho que varrer o arquivo até a linha, trabalhar na linha

// PENDENT ISSO parece completamete desnecessário, reativei novamente agora pra ter certeza! (10/05/2020 12:09)
// Conto a Qtd de Caracters da Linha 3 para poder declarar a variável que vai receber seu conteúdo
int Size = 0;
for(int Current_Line = 1 ;getline(&Line_Content, &Line_Size, MyFile) > 0; Current_Line++) {
if(Current_Line == 3) {
Line_Size = strlen(Line_Content) + 1; // Não sei porque mais declarar aqui int Size meio que não rolou por isso coloquei acima (10/05/2020 02:24)
break;
}
}
fclose(MyFile); // Preciso fechar o arquivo aqui pq o Código acima varre o arquivo
MyFile = fopen(Path, "r"); // PENDENT Reabro ele, talvez eu use aqui um rewind (10/05/2020 12:15)

// Line_Size aqui está com valor 23, porém minha Linha tem 21 Caracteres, mas eu aumentei 1 e esse outro 1 deve ser o Terminador (10/05/2020 12:11)
char *Add_Groups = new char[Line_Size]; // Acho que não funcionou bem o Line_Size ser declarado assim aqui nesta posição pq acredito que ele tenha ficado sem tamanho suficiente. E ainda tenho problema com ele pq abaixo ele muda totalmente de valor, é como se ele não recebe-se os valores, o que não sei pq ele não está recebendo valor.
//char *Add_Groups[101]; // Não funciona assim! Com o Outro acima! Testando pra saber se essa linha que está impedindo ele de receber valores!


//while(getline(&Line_Content, &Line_Size, MyFile) > 0)
for(int Current_Line = 1 ;getline(&Line_Content, &Line_Size, MyFile) > 0; Current_Line++) {
if(Current_Line == 3) {

// > Add/Remove/Edit
// varro o conteúdo da Linha mandando para outra variável o que enviarei para o TextCtrl

// ANOTAR que pegando o valor do ponteiro sem * ele pegou o valor inteiro, mas com * Apenas o valor sendo trabalhado no momento (10/05/2020 12:18)
//(gdb) p Line_Content ➤ $2 = 0xa5fd50 "\002 \037> Add/Remove/Edit\003\n"
//(gdb) p *Line_Content ➤ $3 = 2 '\002'

//while(*Line_Content != '\0')
for( ; *Line_Content != '\0'; Line_Content++)
if(*Line_Content != 2) { // STX
if(*Line_Content != 31) { // US
*Add_Groups++ = *Line_Content++; // Isso não está funcionando! Add_Groups recebe Line_Content e se incrementam
} else {
*Add_Groups++ = '\n';

}
if(*Line_Content == 3) { // ETX
*Add_Groups++ = '\n';
*Add_Groups = '\0';
break;
}
}
break;
}
}
fclose(MyFile);
free(Line_Content);
EdGroups->SetValue(Add_Groups);

//ChGroup->Append("> Add/Remove/Edit");

free(Add_Groups);

Acima está uma Gigante ZONA de tanta modificações provisórias, mas a linha que eu esperava que funciona-se é. Isso COMPILA mas Add_Groups não recebe valor nenhum, ele MENTE pra mim fingindo que tudo está OK qdo não está, Eu entendi que essa linha abaixo receberia caracter por caracter e iria para a próxima posição do vetor/variável/caracter
 *Add_Groups++ = *Line_Content++;  

Sei que a culpa é do C++ mas nem sei compilar usando g++ pedindo a ele pra interpretar meu código como C pelo menos um pedaçinho do código. Estou compilando tanto em C, qto em C++ assim
gcc Test.c -o Test -O3 -Wall -pedantic -pedantic-errors -Werror
g++ Test.cpp -o Test `wx-config --libs --cxxflags` -O3 -Wall -pedantic -pedantic-errors -Werror

Porém o código que informo acima não posso compilar em C, pois ele usa bibliotecas da wxWidgets que é toda em C++ como mostro acima a inclusão delas ao compilar

O Meu problema e o porque desse tipo de solução é que: Estou lendo a Linha 3 de um arquivo e não tenho como saber qts caracteres essa linha possue! Motivo que estou usando getlines para isso! Não quero tipo criar um char text[100000] O C me permite fazer text[TAM], mas C++ me proibiu cheio de regrinhas, e agora não aceita eu passar o valor do ponteiro pro outro!

Alguma idéia? Desculpe a pergunta de forma enrolada, despreparada, é que realmente estou muito chateado com esse incomodo! E se eu não consegui resolver terei que colocar uma solução provisória FEIA até no futuro eu entender melhor C++ suas Novas regras e ficará essa pendência pra ser resolvida!

Nunca me senti tão desrespeitado pelo C++.


  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 11/05/2020 - 03:41h

Começando pelo fim.

Nick-us escreveu:

Nunca me senti tão desrespeitado pelo C++.


Hehehe... A linguagem é o que é. Quem desrespeitou as regras delas foi você. Ela só está reclamando do mal que você fez a ela. ;)

Neste momento fiquei mesmo desanimado! Eu ainda estou aprendendo C e falta um Mundo de coisas para eu entender! Acontece que estou fazendo um programinha usando a wxWidgets que é C++. E por mais que eu me esforce pra escrever em C tudo o que eu posso, começo a perceber que o compilador não me compreende e desconfio severamente que ele está tratando o meu código como C++ em todos os casos!


Se é um compilador C++, não adianta fingir que é outra coisa. C++ parece muito com C em muitos pontos, mas é outra linguagem, com várias regras diferentes, mesmo em coisas básicas, tais como tipos de dados.

Se você quer que um bloco de código se comporte totalmente como C, compile-o com um compilador C, e junte com o código C++ apenas na hora de invocar o linker.

Contudo, eu sou uma daquelas pessoas que consideram o C++ melhor que o C, pelo motivo de que ele ajuda mais você a não fazer algumas bobagens óbvias do ponto de vista semântico, mas que não refletem essa questão semântica sintaticamente em C. Por exemplo: usar um ponteiro para dados não constantes para apontar para dados que são constantes é um erro semântico em qualquer linguagem que possua tipos de dados distintos, o que inclui o C e o C++. Nesse caso, essas características semânticas podem ser expressas sintaticamente e, em o sendo, o compilador pode forçar você a não misturar essas coisas distintas. E o compilador C++ faz isso de modo mais enérgico que o C. (O C também poderia ser enérgico, se quisesse, mas, por vários fatores — e suspeito que o principal fator entre eles sejam manter compatibilidade com código antigo — deliberadamente escolheu não ser.)

Montei um exemplo bonito de um ponteiro usando um vetor de char, salvei para que eu use como consulta, para usar qdo fosse precisar, então hoje qdo coloquei no meu código em C++ o compilador reclama me importuna e nem obedece as regras que eu havia com tanta dificuldade em aprender!

Aprendi com Paulo aqui no Fórum a compilar com TODOS os avisos ao máximo ligado, demorei pra entender isso, agora que entendi achei o máximo, venho resolvendo inúmeras reclamações do compilador e com dificuldades em cada uma delas, mas o compilador não tem nenhum respeito, parece uma perseguição!

CASO: O Exemplo abaixo aprendi na Internet, uma forma de passar valores de um ponteiro pro outro, e eu usaria isso para tratar a String recebida podendo modificá-la e etc... Isso abaixo funciona perfeitamente em C
      while(*pA != '\0') // Repete o while até encontrar em pA o fim de string
*pB++ = *pA++; // pB recebe pA e se Incrementam
*pB = '\0';

Tentei fazer algo similar em C++ e o compilador tá estragando tudo! Ele não aceita uma simples declaração como:
char *Nome = "Nick"; 


Esse é um exemplo de erro semântico com desdobramentos sintáticos a que eu me referi acima.

Tanto em C quanto em C++, o elemento sintático “"Nick"” é uma constante literal de string. Sendo uma constante, e tipo de "Nick" é “array com 5 elementos do tipo const char”. Como todo array, ele decai para um tipo ponteiro para o primeiro elemento quando utilizado em qualquer expressão que não seja sua declaração ou como operando de sizeof ou do operador unário & (ou ainda, no caso do C++, na hora de resolver argumentos de templates).

E qual o tipo do primeiro elemento? Não é const char? Então por que tentar atribuí-lo a um ponteiro para char não-constante? Isso é um erro semântico — seja em C++, seja em C!

O problema é que o C propositalmente — e, na minha opinião, bisonhamente — cria uma exceção para constantes literais de strings, dizendo que elas podem ser atribuídas diretamente a ponteiros para caracteres não-constantes, ainda que o compilador tenha meios de fazer com que a constante literal de string seja disposta em memória com proteção de ser somente para leitura (como, por sinal, têm e efetivamente fazem os compiladores modernos para nossos sistemas em arquitetura amd64/x86-64).

------ Contextualização histórica ------
Essa exceção do C é uma herança de tempos antigos em que, primeiramente, não existia a palavra-chave const na linguagem (antes do primeiro padrão da linguagem, que foi publicado em 1989; e, por sinal, const foi implementado primeiro em C++, e trazido para o C quando se viu que ela ajudava a tornar a programação mais segura), e, em segundo lugar, nem sempre se podia proteger a memória que guardava as constantes do programa (sobretudo em microcomputadores, mas mesmo em algumas máquinas de maior porte da época, não existiam tantos mecanismos de proteção de acessos a memória como existem hoje).

Quando veio o padrão de 1989 do C, achou-se por bem não criar um problema de compatibilidade para todos os programas que já usavam algo como “char *pA="Nick";”, dizendo-se que o decaimento de constantes literais de strings seria para ponteiros para caracteres, em vez de ponteiros para caracteres constantes.

(Às vezes eu fico cá pensando com meus botões se não foi um mero esquecimento: uma vez que a incorporação de const foi uma ação tardia do comitê de padronização, talvez tenham esquecido de rever o impacto dessa adoção em algumas partes do padrão que talvez já tivessem sido escritas, e talvez uma dessas partes fosse justamente a que descrevia o comportamento de constantes literais de strings. Acho também que foi uma escolha com resultado contraproducente: poder usar ponteiro para dados comuns só fez com que quase ninguém se esforçasse para usar ponteiros para dados constantes, mesmo que os dados sejam efetivamente constantes. Quanto mais tempo passou e continua passando, maior se vem tornando a quantidade de código sintaticamente válido mas semanticamente errado que terá ser corrigido para que o C possa requerer o uso de uma sintaxe que reflete o que já é semanticamente feito pelos compiladores.)
------ Fim da contextualização histórica ------

De todo modo, o fato é que o C tem essa infeliz característica de poder ter dados efetivamente constantes referenciados por ponteiros para dados não-constantes, e o C++ muito apropriadamente não copiou essa característica bisonha. Em C++, se o dado é constante, o ponteiro para ele também o é, e qualquer variável que receba tal ponteiro terá ter um tipo que explicite que o dado é constante.

Em C++, portanto, você tem de fazer do seguinte modo.
const char *pA="Nick";  // OK: array com 5 elementos do tipo const char decai para ponteiro para const char, e é atribuído a variável do mesmo tipo. 


Note que o código acima também é perfeitamente válido em C. Então eu sugiro que você passe a deixar explícito no seu código quando você que apontar para dados constantes, de modo a nunca incorrer em erro semântico, mesmo que o erro semântico não produza também um erro sintático.

Apanhei muito pra resolver isso, e o compilador não fica satisfeito! Eu preciso fazer isso funcionar
*pB++ = *pA++;  

Mas não tenho a mínima idéia de como fazer isso! Gastei dias e nada! Abaixo vou mostrar o trecho do código em C++ que estou tentando fazer funcionar e explicarei porque! Ele já ficou uma ZONA de tanta coisa que comentei, modifiquei gerando muito mais confusão pra mim!
// FAZENDO ➤ Ler a Linha 3 do arquivo para EdGroups. Sendo que a cada Campo Lido preciso alimentar ChGroup (10/05/2020 12:05)

MyFile = fopen(Path, "r");
size_t Line_Size; // Posso também chutar um valor para Line_Size que seria o Tamanho da linha, pois getline calcula automaticamente pra mim se eu errar, aqui informei vazio né.
char *Line_Content;

// Tenho que varrer o arquivo até a linha, trabalhar na linha

// PENDENT ISSO parece completamete desnecessário, reativei novamente agora pra ter certeza! (10/05/2020 12:09)
// Conto a Qtd de Caracters da Linha 3 para poder declarar a variável que vai receber seu conteúdo
int Size = 0;
for(int Current_Line = 1 ;getline(&Line_Content, &Line_Size, MyFile) > 0; Current_Line++) {
if(Current_Line == 3) {
Line_Size = strlen(Line_Content) + 1; // Não sei porque mais declarar aqui int Size meio que não rolou por isso coloquei acima (10/05/2020 02:24)


No seu programa não vai fazer muita diferença mas, num caso geral, eu sugiro que você não mexa na variável que indica o tamanho alocado para linha lida.

Como o tamanho alocado e o comprimento efetivo são semanticamente diferentes e também geralmente são diferentes na prática (e o código acima indica que você sabe dessa diferença prática), utilize, sim, uma segunda variável para representar o comprimento da linha lida.

         break;
}
}
fclose(MyFile); // Preciso fechar o arquivo aqui pq o Código acima varre o arquivo
MyFile = fopen(Path, "r"); // PENDENT Reabro ele, talvez eu use aqui um rewind (10/05/2020 12:15)


Sim, use rewind(). É melhor.

   
// Line_Size aqui está com valor 23, porém minha Linha tem 21 Caracteres, mas eu aumentei 1 e esse outro 1 deve ser o Terminador (10/05/2020 12:11)


O mais provável é que o 22º caráter seja o indicador de fim de linha, que não é descartado pela função getline(). Se você não quiser mantê-lo, deve descartá-lo explicitamente após a leitura.

   char *Add_Groups = new char[Line_Size]; // Acho que não funcionou bem o Line_Size ser declarado assim aqui nesta posição pq acredito que ele tenha ficado sem tamanho suficiente. E ainda tenho problema com ele pq abaixo ele muda totalmente de valor, é como se ele não recebe-se os valores, o que não sei pq ele não está recebendo valor. 


O valor muda porque você passa novamente ‘&Line_Size’ como argumento para getline() mais abaixo. Por isso mesmo, eu insisto: se você quer representar semanticamente uma outra coisa, use outra variável.


//char *Add_Groups[101]; // Não funciona assim! Com o Outro acima! Testando pra saber se essa linha que está impedindo ele de receber valores!


A linha que esta comentada acima declararia um array com 101 elementos do tipo ponteiros para caracteres. Não creio que você quisesse isso.



//while(getline(&Line_Content, &Line_Size, MyFile) > 0)
for(int Current_Line = 1 ;getline(&Line_Content, &Line_Size, MyFile) > 0; Current_Line++) {
if(Current_Line == 3) {

// > Add/Remove/Edit
// varro o conteúdo da Linha mandando para outra variável o que enviarei para o TextCtrl

// ANOTAR que pegando o valor do ponteiro sem * ele pegou o valor inteiro, mas com * Apenas o valor sendo trabalhado no momento (10/05/2020 12:18)
//(gdb) p Line_Content ➤ $2 = 0xa5fd50 "\002 \037> Add/Remove/Edit\003\n"
//(gdb) p *Line_Content ➤ $3 = 2 '\002'

//while(*Line_Content != '\0')
for( ; *Line_Content != '\0'; Line_Content++)
if(*Line_Content != 2) { // STX
if(*Line_Content != 31) { // US
*Add_Groups++ = *Line_Content++; // Isso não está funcionando! Add_Groups recebe Line_Content e se incrementam


Parece-me que você não deveria incrementar Line_Content aqui dentro, já que ela já está sendo incrementada pela terceira expressão do for.

Mas isso, embora provavelmente errado, acaba sendo um problema menor. Note que ao alterar os valores dos ponteiros, você não vai mais apontar para os primeiros caracteres de cada um, mas sim para o que tiver acabado de ser copiado na iteração corrente do laço de repetição. Assim sendo, o mais provável é que, no final da cópia, os dois ponteiros fiquem apontando para uma posição (ou duas, dado que há incrementos em dois locais diferentes ao mesmo tempo) após o terminador da string, o que significa que você vai apontar para dados que nem mesmo conhece e que nem ao menos pertencem aos arrays.

Como ambos os ponteiros foram dinamicamente alocados (um através de getline() e o outro com new []), isso é particularmente mais grave, porque você não vai conseguir desalocá-los e, se tentar fazê-lo, os resultado são imprevisíveis.

Uma forma de corrigir isso (além da que eu apresento mais abaixo para substituir esse bloco inteiro) é você ter ponteiro adicionais para percorrer os espaços que foram alocados para LineContent e Add_Groups, mantendo elas próprias inalteradas, para que você possa tanto lembrar de onde as string começam quanto para poder desalocá-las quando for a hora de fazê-lo. Uma forma seria trocar a linha contendo o for acima para algo como
for(char *pCont=Line_Content, *pGroups=Add_Groups; *pCont; ++pCont++, ++pGroups) 

e depois trocar todas as ocorrências de Line_Content e Add_Groups dentro do laço de repetição por pCont e pGroups, respectivamente, e tirar alguns dos incrementos desses ponteiros dentro do laço de repetição, já que eles já estão sendo incrementados pela terceira expressão na linha de controle.

               } else {
*Add_Groups++ = '\n';

}
if(*Line_Content == 3) { // ETX
*Add_Groups++ = '\n';
*Add_Groups = '\0';
break;
}
}
break;
}
}
fclose(MyFile);
free(Line_Content);


Essa desalocação será inválida porque você mudou o valor do ponteiro, a não ser que implemente a correção que eu indiquei acima.

   EdGroups->SetValue(Add_Groups);

//ChGroup->Append("> Add/Remove/Edit");

free(Add_Groups);


Essa desalocação será inválida porque você mudou o valor do ponteiro, a não ser que implemente a correção que eu indiquei acima.

Mas mesmo que estivesse certo anteriormente (ou que você implemente a correção indicada), se você alocou com new[], desaloque com delete[]. Caso contrário, o resultado é imprevisível, com chances de fazer o programa capotar.

Mas melhor ainda, já que você está usando C++, é substituir todos esses ponteiros e operações de alocação e liberação implícitas ou explícitas por variáveis do tipo std::string, e também o trabalho com arquivos ao estilo do C por acesso a arquivo no modo padronizado pelo C++, com std::ifstream. Seu código ficaria muito mais limpo e menos propenso a erros. (Note que eu suprimi a primeira leitura do arquivo, porque ele é desnecessária não apenas nesta versão, mas o teria sido também na sua, se você não tentasse alocar espaço para o objeto antecipadamente.)

// No ínicio do arquivo
#include <fstream>
#include <string>

// Na sua função.
std::ifstream MyFile(Path);
std::string LineContent, AddGroups;
unsigned lineNumber=0u;
while(getline(MyFile, LineContent)){
if(++lineNumber==3){
for(char c: LineContent)
switch(c){ // Uso switch em vez da tripa de ifs porque tende a gerar código mais eficiente, especialmente para um conjunto pequeno de valores possíveis.
default:
AddGroup+=c;
break; // Esse break é do switch, não do for; para sair de loops dentro de um switch tem-se de usar goto.
case '\3': // ETX
AddGroups+=c;
AddGroups+='\n';
// Note o fall-through: aproveita o goto que está abaixo.
case '\0': // Supõe que o terminador de strings do C termina a string no arquivo. Isso não necessariamente é verdade para strings do C++, que podem conter nulos sem problemas (desde que não sejam convertidas de/para strings do C).
goto end_copy;
case '\37': // US (037 é a expressão em base octal do valor 31 em base decimal).
AddGroups+='\n';
// Fall-through: aproveita o break que está abaixo.
case '\2': // STX: não faz nada (no seu programa também não fazia).
break;
}
end_copy:
break; // Sai do while.
}
}
EdGroups->SetValue(AddGroups);


Note como não precisa fechar o arquivo nem desalocar nada: os destrutores dos objetos fazem isso por você quando eles saírem de escopo.

Acima está uma Gigante ZONA de tanta modificações provisórias, mas a linha que eu esperava que funciona-se é. Isso COMPILA mas Add_Groups não recebe valor nenhum, ele MENTE pra mim fingindo que tudo está OK qdo não está, Eu entendi que essa linha abaixo receberia caracter por caracter e iria para a próxima posição do vetor/variável/caracter
 *Add_Groups++ = *Line_Content++;  

Sei que a culpa é do C++ mas nem sei compilar usando g++ pedindo a ele pra interpretar meu código como C pelo menos um pedaçinho do código.


Nada disso. Os erros que você cometeu, sobretudo quanto a mudar valores que deveriam permanecer constantes, não têm nada a ver com o C++ ou com o compilador. Continuariam erros se você usasse um compilador C.

E, por sinal, de novo erros semânticos, que, não tendo reflexo na sintaxe (mesmo em C++) não podem ser identificados pelo compilador.

Estou compilando tanto em C, qto em C++ assim
gcc Test.c -o Test -O3 -Wall -pedantic -pedantic-errors -Werror
g++ Test.cpp -o Test `wx-config --libs --cxxflags` -O3 -Wall -pedantic -pedantic-errors -Werror

Porém o código que informo acima não posso compilar em C, pois ele usa bibliotecas da wxWidgets que é toda em C++ como mostro acima a inclusão delas ao compilar

O Meu problema e o porque desse tipo de solução é que: Estou lendo a Linha 3 de um arquivo e não tenho como saber qts caracteres essa linha possue! Motivo que estou usando getlines para isso! Não quero tipo criar um char text[100000] O C me permite fazer text[TAM], mas C++ me proibiu cheio de regrinhas, e agora não aceita eu passar o valor do ponteiro pro outro!


Já mostrei uma alternativa, que é usar objetos do C++, em vez de se sacrificar com os recursos mais primitivos do C.

Mas se quiser de todo jeito fazer em C ou num estilo C-like, você ainda pode ler o arquivo numa única passada, e alocar a variável quando chegar até a terceira linha (até porque você só fez isso na primeira vez em que fez a leitura no código acima). O problema com isso é que existem caracteres no arquivo de entrada que se tornam dois caracteres na hora de converter, e a forma atual que você usa para alocar a string de destino não leva isso em consideração, mas deveria.

Uma correção é migrar logo para C++, deixando de ser C-masoquista. :)

Outra possibilidade é, ao alocar a string de destino, supor o pior caso e multiplicar por dois o tamanho da linha lida.

E existe ainda a possibilidade — que eu definitivamente não recomendo — de ir realocando a string de destino a cada caráter lido. Nesse caso você não poderá usar new []/delete[], mas sim malloc()/realloc()/free(),. Não poderá também usar um ponteiro como para fazer a cópia de caracteres com algo como “*pGroups++=*pCont++;” (ou “*pGroups=*pCont;”, já que a linha de controle do for já faz o incremento dos ponteiros), pois realloc() pode resolver mover os dados Add_groups para outra região de memória, invalidando o valor de pGroups; em lugar disso, você terá de trabalhar com um índice que indica o deslocamento em relação ao primeiro elemento (por exemplo: “Add_Groups[indice]=*pCont

Alguma idéia? Desculpe a pergunta de forma enrolada, despreparada, é que realmente estou muito chateado com esse incomodo! E se eu não consegui resolver terei que colocar uma solução provisória FEIA até no futuro eu entender melhor C++ suas Novas regras e ficará essa pendência pra ser resolvida!

Nunca me senti tão desrespeitado pelo C++.


O C++ não tem culpa de nada aqui. As confusões são fruto de entendimento inadequado, e dariam problema também em C, Pascal, Assembly ou qualquer outra linguagens em que existam ponteiros.

Aliás, se ponteiros o deixam confuso, eis mais uma boa razão para preferir C++ a C. Ainda existem ponteiros em C++ mas, como ilustrou o programa que eu propus acima, seu uso direto para tarefas simples tende a ser menos necessário e mais controlado.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)

3. Re: Tristeza com Ponteiros em C++ [RESOLVIDO]

Nick Us
Nick-us

(usa Slackware)

Enviado em 10/05/2020 - 13:54h

Para terem uma idéia do quanto é difícil aprender com tanto material na internet que não funciona! Olha esse site e seu exemplo:
https://pt.wikiversity.org/wiki/Curso_de_C%2B%2B/Tipos_de_dados#Strings

Resultado ao compilar! Os erros abaixo é porque TUDO mudou, então se pega um exemplo pra estudar, dá uma confusão enorme pra entender!
g++ Test.cpp -o Test -O3 -Wall -pedantic -pedantic-errors -Werror
Test.cpp: In function ‘int main()’:
Test.cpp:9:4: error: ‘strcpy’ was not declared in this scope
9 | strcpy(frase,"Tipos de dados"); // copia "Tipos de dados" para frase.
| ^~~~~~
Test.cpp:3:1: note: ‘strcpy’ is defined in header ‘<cstring>’; did you forget to ‘#include <cstring>’?
2 | #include <iostream>
+++ |+#include <cstring>
3 | using namespace std;
Test.cpp:12:13: error: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
12 | frase1 = "Curso de C++";


OBS não preciso de solução pra isso acima! É apenas um exemplo da dificuldade que passo! As coisas mudam! E acabo ficando perdido, pq aprendo errado! Anoto errado, e qdo vou usar não funciona, tenho que buscar respostas do porque não funciona e nem sempre se acha!


4. Re: Tristeza com Ponteiros em C++ [RESOLVIDO]

Mauricio Ferrari
maurixnovatrento

(usa Slackware)

Enviado em 10/05/2020 - 13:59h


Entendo sua situação, logo tentarei ajudar.

___________________________________
Conhecimento não se Leva para o Túmulo.


5. Eu jamais vou entender programadores que escrevem o código antes de começar a debugar

Pedro De Oliveira
PedroExpedito

(usa Debian)

Enviado em 10/05/2020 - 14:14h

Quando joguei seu código no VIM você não declarou algumas variaveis não declaradas, vou tentar ajudar sobre oque entendi

você resolve isso
```char *Nome = "Nick"; ```
com isso que também funciona em C
``` char Nome[] = "Nick";```
também pode usar o tipo string do CPP
``` string Nome = "Nick";

sobre isso
while(*pA != '\0') // Repete o while até encontrar em pA o fim de string
*pB++ = *pA++; // pB recebe pA e se Incrementam
*pB = '\0';

que bagunça , podia usar a strcpy do C

também pode fazer uma função para isso

no caso de usar string pode usar string mesmo
exemplo
int main()
{
std::string myString = "Hello, there!";

std::string myOtherString = myString; //Makes a copy of myString


}


Só consegui ajuda nessa parte,olha sobre o seu mindset de resolver problemas é muito estranho atribuir sentimentos a determinada ferramenta o compilador é só outro programa que transcreve X para outra coisa no caso CPP para Assembly.

Não passe dias tentando resolver problemas, pesquisa na internet em ingles que é sucesso, ou pede ajuda.


6. Re: Tristeza com Ponteiros em C++ [RESOLVIDO]

Nick Us
Nick-us

(usa Slackware)

Enviado em 10/05/2020 - 14:16h

mauricio123 escreveu: Entendo sua situação, logo tentarei ajudar.
__________________________________
Conhecimento não se Leva para o Túmulo.

Obrigado Maurício, eu fui olhar o seu Site o Link: http://linguagemcfacil.mozello.com/conteudos/params/post/2016097/exibicao-definitiva-dos-caracteres-...
E tenho que dizer que ficou super maneiro sua explicação! Você abordou de muitas formas e soluções diferentes! Parabéns mesmo, pq na minha opinião ficou muito BOM, e costumo ser muito crítico!

Outro ponto, não sei se vai te interessar, mas gostaria de contribuir com isso:
No Link: http://linguagemcfacil.mozello.com/extra/
Eu conheço uma Tabela que eu sempre uso, muito boa mesmo. De uma olhadinha ela é super completa e simples pra consultar:
https://theasciicode.com.ar/


7. Re: Tristeza com Ponteiros em C++ [RESOLVIDO]

Nick Us
Nick-us

(usa Slackware)

Enviado em 10/05/2020 - 14:44h

PedroExpedito escreveu:Quando joguei seu código no VIM você não declarou algumas variaveis não declaradas, vou tentar ajudar sobre oque entendi

Tipo o Código é apenas 1 pedaço, mostrei apenas o pedaço problemático, porém minha dificuldade é só na linha que mencionei ao passar caracter a caracter para outra variável ponteiro
*Add_Groups++ = *Line_Content++; 


você resolve isso
```char *Nome = "Nick"; ```
com isso que também funciona em C
``` char Nome[] = "Nick";```
também pode usar o tipo string do CPP
``` string Nome = "Nick";
Neste caso eu não estou resolvendo isso, pq isso não é o problema! E essa solução não serve, pq no momento que eu colocar char Nome[] = "Nick" ele terá apenas 4 espaços pra eu usar. Então imagina qdo essa variável receber 1000 caracteres o que aconteceria? Isso eu resolvi usando NEW na declaração da variável! assim:
char *Add_Groups = new char[Line_Size]; 

Repare que eu não sei o tamanho da String, por isso Line_Size é uma variável modificável.

sobre isso
while(*pA != '\0') // Repete o while até encontrar em pA o fim de string
*pB++ = *pA++; // pB recebe pA e se Incrementam
*pB = '\0';

que bagunça , podia usar a strcpy do C

A função strcpy apaga a String de destino, o que talvez eu pudesse usar seria strcat porém compreenda que não posso usar strcat pq a declaração inicial é ponteiro usada por getline que ainda não sei exatamente como usar de outra forma, e não acho que ele vá aceitar um char simples pq ele muda o tamanho da variável conforme o tamanho que ela receber dinamicamente. Line_Content possue a Linha Inteira que estou trabalhando, mas como disse eu preciso pegar essa linha remover caracteres que não serão usados, substituir outros por \n pegar pedaços dessas Strings montadas, pq a Linha possue Campos, entende? Cada campo vai pra um lugar diferente, então não é uma String que usarei inteira, e sim uma String que vou separar em 10 ou 100 e cada pedaço desse vai pra um lugar, motivo que após receber a Linha inteira, faço uma varredura de caracter por caracter. Tipo LETRA a LETRA 1 letra de cada vez até o fim inteiro da String. No código que postei no exemplo, ele está simplificado estou tratando apenas os Caracteres STX, US, ETX mas existem outros que vou incluir qdo o Código estiver funcionando!
getline(&Line_Content, &Line_Size, MyFile) > 0 


no caso de usar string pode usar string mesmo
exemplo
int main()
{
std::string myString = "Hello, there!";
std::string myOtherString = myString; //Makes a copy of myString
}
Não esqueça que qdo faço a leitura não estou lendo uma String pq não existe uma String. Existem caracteres apenas. É um texto que usa caracteres especiais como separadores de registros que não são iguais e nem mesmo seguem um tamanho de string. Posso ter nessa linha 21 caracteres no mínimo, mas essa linha pode passar de 10 mil caracteres, e com isso aumenta a qtd de caracteres separadores de cada String, motivo pelo qual leio caracter por caracter para encontrar esses separadores, modificar eles passando para outra variável. Entenda. O Caracter Especial por exemplo STX não é exibido na Tela entende? O Caracter US também não, eu ignoro alguns deles, o US eu substituo por \n por isso trato 1 a 1.

Só consegui ajuda nessa parte,olha sobre o seu mindset de resolver problemas é muito estranho atribuir sentimentos a determinada ferramenta o compilador é só outro programa que transcreve X para outra coisa no caso CPP para Assembly.
Concordo plenamente com você, é que poxa parece perseguição, esse programa está com 1500 linhas e não teve uma única linha sequer que não tenha dado muito trabalho pra solucionar! E um dos trabalhos mais cansativos foi definir Caracteres Especiais para lidar com o Arquivo, minimizar ao máximo a leitura e a modificação desse arquivo, estudar e pensar em cada erro que poderia acontecer com alguma falha, e vc sabe a wxWidgets é bastante cheia de vontadezinhas também, ela inventa BUGS, coisas malucas, coisas sem sentido, coisas que deveria funcionar e não funcionam, necessitando remendos horríveis, e em algumas situações ainda incompletos, sua documentação é extremamente confusa o que escrevem não funciona, misturam Syntax com palavras que nada tem a ver e por ai vai!

Não passe dias tentando resolver problemas, pesquisa na internet em ingles que é sucesso, ou pede ajuda.

Eu pesquiso, as vezes é fácil, as vezes é super confuso. No Caso de Ponteiros, TODO Mundo parece amar somente INT existem milhares de explicação para o INT e ninguém nunca fala do pobrezinho do char! parece que odeiam char.... Exemplos de char são super escassos!




8. Re: Tristeza com Ponteiros em C++

Nick Us
Nick-us

(usa Slackware)

Enviado em 10/05/2020 - 14:59h

Acrescentando mais informação.
Vou detalhar mais! Pensem da seguinte forma, Em C o Código abaixo funciona perfeitamente!

char *pA = "Pensem aqui em uma Linha com 10 mil caracteres"
char *pB;
while(*pA != '\0') // Repete o while até encontrar em pA o fim de string
*pB++ = *pA++; // pB recebe pA e se Incrementam

Explicando o que o código acima faz: Ele Lê o vetor pA caracter a caracter ou seja uma letra de cada vez. Então dentro do while ou for o que seja, eu analiso cada letra dessa entende? Após analisar cada letra eu tomo uma decisão, seja ignorando a letra ou modificando essa letra por outra...
Além disso qdo eu encontro por exemplo o Caracter US que é o 31 da Tabela ASCII eu Salvo a variável pB em outro lugar no Caso em um wxChoice. Então adiciono nela um \n e envio para outro lugar no caso um TextCtrl, Então APAGO pB logo ela volta a estar vazia, e vai continuar recebendo os caracteres restantes. E isso continua até que a String inteira pA seja completamente varrida.

BOM, eu não preciso de ajuda nenhuma pra implementar o que disse acima, pq eu já sei fazer isso!
O que estou tendo dificuldade é fazer essa linha funcionar
*pB++ = *pA++; // pB recebe pA e se Incrementam 

Que no meu Código acima é:
*Add_Groups++ = *Line_Content++; // Isso não está funcionando! 

O Código compila, porém no código acima, o correto seria a LETRA que está em Line_Content deveria ir para Add_Groups porém não está INDO, ou seja o programa está fingindo fazer o que não está fazendo! Achei inicialmente que a Culpa seria do Tamanho dinâmico da variável, mas não é, pq já coloquei ela com 1000 caracteres fixos por exemplo. A Linha acima Add_Groups recebe 1 caracter da String entende? E após receber esse Caracter ele avança para a próxima posição do vetor para receber outro caracter e se repete, porém não funciona

Porque não posso usar um char que não seja ponteiro? Justamente pq getline não vai aceitar! veja sua syntax:
ssize_t getline(char **lineptr, size_t *n, FILE *stream); 

Eu não sei fazer o getline aceitar um char normal, imaginando que isso seria possível.
Não posso usar fgets pq eu não sei o tamanho da linha! E obviamente declarar por exemplo char Text[500000] fica bastante feio e estranho né?


9. Re: Tristeza com Ponteiros em C++ [RESOLVIDO]

Mauricio Ferrari
maurixnovatrento

(usa Slackware)

Enviado em 10/05/2020 - 21:48h


Nick-us escreveu:

mauricio123 escreveu: Entendo sua situação, logo tentarei ajudar.
__________________________________
Conhecimento não se Leva para o Túmulo.

Obrigado Maurício, eu fui olhar o seu Site o Link: http://linguagemcfacil.mozello.com/conteudos/params/post/2016097/exibicao-definitiva-dos-caracteres-...
E tenho que dizer que ficou super maneiro sua explicação! Você abordou de muitas formas e soluções diferentes! Parabéns mesmo, pq na minha opinião ficou muito BOM, e costumo ser muito crítico!

Outro ponto, não sei se vai te interessar, mas gostaria de contribuir com isso:
No Link: http://linguagemcfacil.mozello.com/extra/
Eu conheço uma Tabela que eu sempre uso, muito boa mesmo. De uma olhadinha ela é super completa e simples pra consultar:
https://theasciicode.com.ar/


Ajudou muito, obrigado! Agradeço seu apoio.

___________________________________
Conhecimento não se Leva para o Túmulo.


10. Re: Tristeza com Ponteiros em C++ [RESOLVIDO]

Mauricio Ferrari
maurixnovatrento

(usa Slackware)

Enviado em 10/05/2020 - 22:08h


Nick-us escreveu:

Acrescentando mais informação.
Vou detalhar mais! Pensem da seguinte forma, Em C o Código abaixo funciona perfeitamente!

char *pA = "Pensem aqui em uma Linha com 10 mil caracteres"
char *pB;
while(*pA != '\0') // Repete o while até encontrar em pA o fim de string
*pB++ = *pA++; // pB recebe pA e se Incrementam

Explicando o que o código acima faz: Ele Lê o vetor pA caracter a caracter ou seja uma letra de cada vez. Então dentro do while ou for o que seja, eu analiso cada letra dessa entende? Após analisar cada letra eu tomo uma decisão, seja ignorando a letra ou modificando essa letra por outra...
Além disso qdo eu encontro por exemplo o Caracter US que é o 31 da Tabela ASCII eu Salvo a variável pB em outro lugar no Caso em um wxChoice. Então adiciono nela um \n e envio para outro lugar no caso um TextCtrl, Então APAGO pB logo ela volta a estar vazia, e vai continuar recebendo os caracteres restantes. E isso continua até que a String inteira pA seja completamente varrida.

BOM, eu não preciso de ajuda nenhuma pra implementar o que disse acima, pq eu já sei fazer isso!
O que estou tendo dificuldade é fazer essa linha funcionar
*pB++ = *pA++; // pB recebe pA e se Incrementam 

Que no meu Código acima é:
*Add_Groups++ = *Line_Content++; // Isso não está funcionando! 

O Código compila, porém no código acima, o correto seria a LETRA que está em Line_Content deveria ir para Add_Groups porém não está INDO, ou seja o programa está fingindo fazer o que não está fazendo! Achei inicialmente que a Culpa seria do Tamanho dinâmico da variável, mas não é, pq já coloquei ela com 1000 caracteres fixos por exemplo. A Linha acima Add_Groups recebe 1 caracter da String entende? E após receber esse Caracter ele avança para a próxima posição do vetor para receber outro caracter e se repete, porém não funciona

Porque não posso usar um char que não seja ponteiro? Justamente pq getline não vai aceitar! veja sua syntax:
ssize_t getline(char **lineptr, size_t *n, FILE *stream); 

Eu não sei fazer o getline aceitar um char normal, imaginando que isso seria possível.
Não posso usar fgets pq eu não sei o tamanho da linha! E obviamente declarar por exemplo char Text[500000] fica bastante feio e estranho né?



Eu posso estar escrevendo besteira, mas:

*Line_Content++;
strcpy(*Add_Groups, *Line_Content);
*Add_Groups++;


Eu nunca usei tanto ponteiros assim desse jeito, por isso não tenho muita prática com isso. Mas tenta isso aí.


___________________________________
Conhecimento não se Leva para o Túmulo.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts