Ir ao conteúdo

arfneto

Membro Pleno
  • Posts

    6.526
  • Cadastrado em

  • Última visita

Tudo que arfneto postou

  1. Como são dois níveis e poucas opções if/else é mais simples e legível. Ou use funções distintas para retirada e depósito. E if/else nas funções
  2. Leia as listas para vetores de strings e apenas use um loop lendo os itens da primeira lista. Dentro dele para cada elemento da primeira lista você percorre a segunda até achar o cara ou ate ela terminar. Se terminou sem achar ele não está repetido na segunda e você pode mostrar. Se está passa para o próximo item na primeira lista. Como faria com as listas em papel na sua mesa. Só isso. Aposto que ela não pode usar essas estruturas --- containers --- de STL, como listas, vetores e filas e tal. É um exercício aparentemente sobre loops, muito básico. Mas se puder usar set é o mais apropriado, certo? Estamos falando de intersecção de conjuntos afinal. É mais intuitivo. Veja como pode ser mais fácil: #include <iostream> #include <set> using namespace std; int main() { std::string lista1[8] { "0", "1", "2", "3", "3", "4", "5", "5" }; std::string lista2[4] { "1", "3", "5", "5" }; std::set <string> B; for (auto valor : lista2) B.insert(valor); // todos em A for (auto valor : lista1) if (B.find(valor) == B.end()) cout << valor << endl; }; Em especial porque list<> não tem .find() e set<> tem. Usando dois conjuntos podia escrever: std::string lista1[8]{ "0", "1", "2", "3", "3", "4", "5", "5" }; std::string lista2[4]{ "1", "3", "5", "5" }; std::set <string> A; std::set <string> B; for (auto valor : lista1) A.insert(valor); // todos em A for (auto valor : lista2) B.insert(valor); // todos em B for (auto valor : A) if (B.find(valor) == B.end()) cout << valor << endl; Que funciona igualzinho. Mas acho que não é o propósito do exercício
  3. "trecho" certo? o -v é outra opção, tem que ter um espaço. Ou pode deixar apenas -std=c17 Estaria ok se você tivesse digitado certo. Com o v grudado ao 7 sua opção vai ser ignorada. Não, não foi e por isso as duas opções fase() e fase1() estão até no programa que você copiou e não viu. Leia atentamente. E escreva atentamente para não incorrer em erro como acima quando não deixou o espaço entre o 7 e o v O -v serve para mostrar a versão do compilador. Não é necessário. Eu recomendo num primeiro momento porque assim pode confirmar que o compilador está usando as opções que você colocou antes... Veja e assim você vê que por exemplo está usando gcc 8.2 e o padrão c17
  4. Não entendo o que quer dizer. Preste atenção: a questão original só foi exposta depois da abertura do tópico. No #5 tem uma solução como pedido, um exemplo. No tópico #8 um OUTRO usuário perguntou sobre como poderia alterar o comportamento para voltar ao início da leitura quando o cara erra ao invés de ficar encalhado em cada opção até o usuário acertar cada senha da série. No programa que você copiou tem as duas funções, fase() e fase1() que você deve ter incluído sem ler. Não adianta explicar de novo o que já disse. Não vai mudar o que está lá escrito, nmo tópico #5, no #8, nos seguintes ou no programa que copiou ontem. Se usa esse programa então poderia lá onde eu te mandei até o desenho da tela e saberia como alterar para poder usar as versões de menos de 30 anos da linguagem que está tentando aprender em 2020. Você não é meu aluno, e se fosse teria no primeiro dia ouvido algo sobre versões e linguagem e tal. O fato desse programa Dev-C++ vir configurado dessa forma é simplesmente uma bobagem. Acho mesmo ***** o cara em 20 de março de 2020, vi agora a data da última versão ainda tenha a cara de pau de deixar como padrão o C de 1989 e o C++ de 1998. E também não entendo como alguém, algum instrutor, escola ou hobbysta usa isso. Você vê em foruns daqui até a Austrália caras explicando como mudar esse troço. Não consigo entender. Vou repetir: Em Tools | Compiler Options você inclui essas letrinhas Só isso. 10 letras. E tecla OK. E o compilador já tinha te mostrado isso na tela... Para comparar, o ambiente que eu uso sequer admite algo anterior a C++ '14 Ninguém vai te ensinar isso. Sequer é um conceito. Preste atenção: antes de 1989 você tinha que declarar int c89() { int i = 0; for (i = 0; i < 4; i = i + 1) { int j = 0; for (j = 0; j < 4; j = j + 1) { printf("i,j = (%d,%d)\n", i, j); } } } E precisava declarar as variáveis fora do loop. E era um porre porque muitas vezes a variável só existia como contador lá dentro mesmo. Num programa grande tinha muito disso. E como elas continuam existindo durante o programa todo era uma chance de erro também. A partir de 89 passou a ser possível escrever int c() { for (int i = 0; i < 2; i = i + 1) for (int j = 0; j < 2; j = j + 1) printf("i,j = (%d,%d)\n", i, j); } Declarando a variável dentro do for que some depois que o comando executa. É só isso: uma comodidade. Grande. Mas não seja ingênuo ao achar que foi só isso que mudou nesses anos todos. A linguagem evoluiu MUITO e ninguém seriamente que ficar de fora. Esse ambiente Dev-C++ é ruim, como é o Code::Blocks. A única razão pra usar isso nos tempos recentes é a sua escola obrigar. Seu patrão não porque eu nunca vi uma empresa usar isso, mas se existir um então será um motivo válido. Cuidado para não superestimar a sabedoria e interesse "deles"
  5. Não entendo o que quer dizer. Você apenas não prestou atenção à conversa toda. Se tivesse feito isso veria que no tópico #5 tem um lugar onde está escrito E saberia onde colocar a tal função, porque lá tem o programa todo, escrito conforme o enunciado... Bem, esse foi mais um caso em que você não prestou atenção... Veja o tópico #8 Se tivesse visto teria entendido que foi escrito assim para ajudar um usuário que perguntou E mais uma coisa que não teve ter notado, no programa que você acaba de copiar e testar: Tem as duas funções: a original conforme o enunciado e essa outra opção escrita para ajudar o usuário no tópico #8 que você não deve ter lido ou entendido... Acho que já expliquei isso com detalhe para você: não é esperto mudar um programa para o formato de 30 anos atrás porque seu ambiente de desenvolvimento está configurado errado. O esperto é incluir como te expliquei com detalhes no tópico 26, a opção certa. Muita coisa importante mudou para muito melhor a partir do C de 89 e do C++ de 98. Seria ingenuidade achar que não. Mesmo esse lance de não poder declarar uma variável no for é um porre e se acha mesmo que deve fazer isso em todos os programas não sei o que dizer... Acha mesmo que não vai ter problemas com os próximos programas? Acha mesmo que a versão C89 de C e a versão C98 de C++, que são as que seu IDE está usando, são as certas em 2020? Acha mesmo que nada esperto apareceu em C desde 1989, 30 anos atrás? Ou em C++ desde 98? Se acha, está errado. E só vai ter mais trabalho. Não deve se sentir culpado em, digamos, virar a página do livro e ver um novo conceito do curso. Sempre vejo alunos que dizer "eu ainda não aprendi isso", mas em se tratando de linguagens e algoritmos e coisas assim, muitas vezes é bem mais simples "virar a página" e ler o que falta do que ficar se debatendo para resolver só com "os conceitos que vi até agora", a menos que o enunciado ou o patrão exija isso. Alguém escreveu Pense nisso
  6. Exato. É assim. Apenas essa "tradução" não é de mão dupla: Se nome_comodo é (char*) (*nome_comodo) é char. Mas se *nome_comodo é char nome_comodo pode ser outra coisa, como você viu aqui. E isso dá muita confusão na teoria e na prática., E cancela um grande número de programas Em especial no caso de char* versus char[] e strings literais tipo "constante" passadas como argumento
  7. Se acompanhou essa discussão toda e em especial se rodou aquele último programa que mostrei deve ter uma boa visão desses cenários todos. Considere essas declarações: char nome_comodo[30]; //[1] int v[100]; // [2] int* x[100]; // [3] int** y; // [4] char** argv; // [5] E mais aquilo tudo sobre const e já deve ter entendido que o contexto é bem maior. &v[0] é sempre o endereço de início de v. Mas não determina v. Veja o caso [1] de que falamos tanto nesse tópico: nome_comodo é de certo modo um ponteiro para char. Isso porque Mas... Veja O que acontece é que muita gente acha que uma coisa é o contrário da outra. Apontar para um char e char*. E mesmo os que sabem que não é não costumam ressaltar a diferença. Está vendo acima? *nome_comodo é um char. Mas nome_comodo não é um ponteiro para char. Seria se você declarasse char* nome_comodo; mas aí nome_comodo iria ocupar só 4 bytes e não 30. E não seria por si só nada válido... &v[0] é a mesma coisa que v. Pode usar de qualquer modo. Fiquei curioso e li aquele artigo em https://www.ime.usp.br/~pf/algoritmos/aulas/pont.html e recomendo esquecer. Tem muitas inconsistências e erros.
  8. Claro que os endereços vão mudar a cada vez que rodar o programa, mas naquela execução era. E o compilador alocou no caso 400 bytes a partir desse endereço e eles são o v[]. Para acessar v[99] você poderia escrever *(v+99) = 99; E assim você vê que C tem aritmética de ponteiros e somou 4X99 ao endereço inicial os valores de V são consecutivos na memória. E seriam mesmo que v fosse int v[10][100]]10]; usando a fórmula que mostrei ontem adicionado 3 minutos depois Recomendo muito rodar esse programa em seu computador. Tem só 40 linhas mas ajuda a entender esse lance de ponteiros, endereços e const isso e isso const
  9. Sim. Formalmente porque sizeof(int*) é 4 e sizeof(int) é 4. adicionado 0 minutos depois E essas são as declarações int* azul; printf("Endereco de azul: [%X]\n", (unsigned int)&azul); int var = 123'456;
  10. Lembrando do passado, eu gostaria que quando eu estava aprendendo isso alguém me mostrasse esses mecanismos assim em um programa.... Por falar nisso, eis o programa que mostrei #include <stdio.h> int main() { int* azul; printf("Endereco de azul: [%X]\n", (unsigned int)&azul); int var = 123'456; printf("Endereco de var: [%X] valor = %d\n", (unsigned int)&var, var); azul = &var; printf("End de azul: [%X] ", (unsigned int)&azul); printf(" Valor de azul = %X\n", (unsigned int)azul); printf("Valor apontado por azul = %d\n", *azul); const int* pConst = (const int*) azul; printf("End de pConst: [%X] ", (unsigned int)&pConst); printf(" Valor de pConst = %X\n", (unsigned int)pConst); printf("Valor apontado por pConst = %d\n", *pConst); int outro = 12; pConst = &outro; printf("Valor apontado por pConst = %d\n", *pConst); int* const pIntConst = &var; printf("Valor apontado por pIntConst = %d\n", *pIntConst); const int* const pMuitoConst = &var; int v[100]; v[0] = 1; v[4] = 4; return 0; } Esqueci de postar... adicionado 3 minutos depois Esse é um problema comum, e estou aqui fechado mesmo então escrevi um programa e mostrei os detalhes para quem tiver dúvida sobre isso. Eu acho que é um inferno, mas ao mesmo tempo é genial e é a razão de C ser tão importante: é muito fácil abstrair conceitos como memória e hardware. Não por acaso Unix foi escrito em C, e Windows. E C++ teve como primeiro compromisso não ser inferior e não perder nada em termos de afinidade com o que o autor de C chamava de systems programming
  11. Uma vez declarado tem seu espaço garantido e reservado sim. Os 4 ou 8 bytes em geral hoje em dia. Isso. Meu entendimento não é relevante. Simplesmente é como estou me dando ao trabalho de explicar. Não é ideia ou interpretação minha. Apenas é assim. "O endereço é o endereço do primeiro elemento" não é correto. O endereço do ponteiro vai ser definido quando o programa é carregado. É constante. É o endereço de uma variável. Talvez você esteja confundindo o endereço do ponteiro com o valor dele. O endereço do ponteiro é o endereço do ponteiro, e é irrelevante em geral. Vou tentar explicar passo a passo porque é uma dúvida comum Mas entenda que não é minha interpretação. É assim. A realidade da alocação em C e provavelmente a razão de ter tanto sucesso como ferramenta. Se você declarar int* azul; azul é um ponteiro para int. E *azul é int. Mas nesse momento *azul não é p%$$a nenhuma porque azul não aponta para nada. Claro, azul tem um endereço na memória. É uma variável. Estaticamente declarada. E não importa. Você pode ver esse endereço com um printf() mas de nada serve. Mas e o valor? Você sequer pode acessar o valor, *azul. Porque a variável não foi inicializada Veja o que um IDE moderno diria se você tentasse imprimir *azul: Ele até se oferece para criar as correções, mas não compila. E se você escrever Aí tudo bem. Posso usar &X e imprimir o endereço de azul. Que de nada serve. Talvez aí esteja sua dificuldade em entender. Ou a de outros. Mas vamos prosseguir, rodando o programa de 1 instrução. Ele mostra no computador de estou usando Endereco de azul: [6FF9CC] Rodando o programa podemos olhar o que tem lá: Viu as '???' ? o valor é 0xCCCCCCCC --- estou compilando para 32 bits, o ponteiro tem 4 bytes. E não aponta para nada Vamos declarar int var = 123'456; Então var é um int e tem um endereço e um valor, um conteúdo. var é o valor. &var é o endereço. '&' é o operador 'address of' nesse caso. e você pode imprimir os dois. Mas vamos ver o que tem lá OK Então var vale 123456. Aspas são um separador de unidades em C, como a gente escreve 1.200 para separar os milhares pode escrever 1'200 em C. Não são considerados. Pode escrever 1'2'3'4'5'6 e o valor vai ser o mesmo, 123456; Mas agora vamos mostrar o endereço de var também e rodar o programa Endereco de azul: [BFF84C] Endereco de var: [BFF840] valor = 123456 E vamos escrever azul = &var; Então o endereço de azul, o ponteiro para int, não muda: nunca vai mudar. Mas o conteúdo, que era indefinido, passa a ser o endereço de var. E vamos rodar o programa e ver o que tem lá: Veja que azul, o ponteiro para int, agora aponta para algo, e esse algo contém 123456, o valor de var. Agora sim *azul é um int válido, porque azul tem o endereço de var, 0xBFF840 e nesse endereço está o valor 123456 Podemos imprimir o endereço de azul agora, que nunca vai mudar. E o conteúdo de azul agora, que vai ser o endereço de var. E o valor para onde azul aponta, o *azul que é um int Veja Endereco de azul: [6FFCCC] Endereco de var: [6FFCC0] valor = 123456 End de azul: [6FFCCC] Valor de azul = 6FFCC0 Valor apontado por azul = 123456 E isso fecha a conta. Se declarar um int**** pMonstro; vai ser a mesma coisa, 4 vezes, uma dentro da outra: ****pMonstro vai ser um int; ***pMonstro vai ser int* **pMonstro vai ser int**; *pMonstro vai ser int***; É a definição, não é minha interpretação. Mas e a coisa de const isso e const aquilo? Vamos ver essa parte também. Vamos declarar const int* pConst = (const int*) azul; Não vou ficar repetindo, mas claro que pConst tem um endereço. E é irrelevante. Toda variável tem um. Constante e imutável. Mas pConst tem um valor, porque foi inicializada com o valor de azul. Então eu posso ver isso no programa E faz todo sentido: var vale 123456; azul tem o endereço de var então *azul vale 123456. Veja as colunas Value e Type pConst tem o valor de azul, então *pConst vale o mesmo, 123456; No programa, vamos mostrar essas novidades: Endereco de azul: [F3F8EC] Endereco de var: [F3F8E0] valor = 123456 End de azul: [F3F8EC] Valor de azul = F3F8E0 Valor apontado por azul = 123456 End de pConst: [F3F8D4] Valor de pConst = F3F8E0 Valor apontado por pConst = 123456 Mas e daí? O que mudou aqui é que pConst é const int* Então eu não posso usar pConst para mudar o valor de var... Veja Não compila, porque a expressão à esquerda tem que ser um valor modificável e *pConst não é. Eis o erro oficial. Pra que serve isso? O grande lance é garantir ao usar algo assim como argumento de uma função, por exemplo, que nada dentro dela vai modificar esse valor. Em especial no caso de char* isso permite que você chame uma função com uma constante tipo funcao("esse valor nao muda"); sem se preocupar com a possibilidade de dentro da função ela tentar alterar o valor da string e cancelar o programa Mas pConst não é constante! Eu posso escrever int outro = 12; pConst = &outro; E vai rodar. Posso até ver o valor de *pConst Endereco de azul: [12FFAC8] Endereco de var: [12FFABC] valor = 123456 End de azul: [12FFAC8] Valor de azul = 12FFABC Valor apontado por azul = 123456 End de pConst: [12FFAB0] Valor de pConst = 12FFABC Valor apontado por pConst = 123456 Valor apontado por pConst = 12 Veja os valores Mas e se fosse diferente? int* const pIntConst = &var; Então agora *pIntConst ainda é um int e pIntConst aponta para var. E var vale 123456. E eu posso imprimir esse valor também: Endereco de azul: [12FF75C] Endereco de var: [12FF750] valor = 123456 End de azul: [12FF75C] Valor de azul = 12FF750 Valor apontado por azul = 123456 End de pConst: [12FF744] Valor de pConst = 12FF750 Valor apontado por pConst = 123456 Valor apontado por pConst = 12 Valor apontado por pIntConst = 123456 E posso ver no programa Como esperado Mas qual é a diferença afinal? Agora eu tenho pIntConst apontando para var. Vamos apontar pIntConst para pConst então, e ver se o valor passa para 12... Não, não vamos. Não compila. Nesse caso pIntConst não pode apontar para outra coisa. É um ponteiro para um endereço constante. E eu posso usar os dois? const int* const pMuitoConst = &var; Sim, claro. Nesse caso não se pode alterar o valor apontado por pMuitoConst e nem se pode fazer pMuitoConst apontar para outro lugar. Espero que quem esteja lendo isso tenha entendido o que significa isso tudo. Sobre a citação Não é um ponteiro constante. Ele se expressou mal apenas. Ou a noção dele de "espécie" dele é muito liberal. O que eu expliquei acima mostra como isso funciona. A gente lê muita coisa errada ou ingenuamente resumida na internet e mesmo nos livros. int v[100]; quer dizer que v é do tipo int[100]; Não é um ponteiro para int, um int*. int aponta para uma área de memória cujo tamanho é sizeof(int) * 100 Sem fantasia, veja V tem um endereço, e apenas os valores que eu defini estão lá alterados. E o tipo de v[] está lá a direita.
  12. Não tem nada de especial no código que eu escrevi e não era para você ter problemas de portabilidade. Esse lance de declarar variáveis no for realmente é muito antigo, faz mais de 20 anos que se usa isso. E para compilar precisava alterar aquela opção no seu compilador. Mas você fez algo errado --- bem errado --- ao copiar: está claro na figura que colocou a função fase() DENTRO de main() e por isso a linha 24 aparece marcada. BEM MARCADA em vermelho... Não reparou? A barra em vermelho? "compilar" é a palavra. E o erro está marcado lá: você colou a função fase() dentro de main() e não é assim que funciona. Quer que eu poste um programa inteiro? #define _CRT_SECURE_NO_WARNINGS #include "stdio.h" #include "stdlib.h" int fase(int etapa, int alvo); int main() { int tentativas = 3; int senhas = 5; int ok = 0; int pre_a = 2; int a = 12; int pos_a = 4; int* p = &a; const int senha[5] = { 1, 99, 17, 57, 50 }; // vai ter 'x' tentativas de acertar as 'y' senhas for (int t = 0; t < tentativas; t = t + 1) { ok = 0; printf("\nTentativa %d de %d\n\n", 1 + t, tentativas); for (int f = 0; f < senhas; f = f + 1) { // se o cara errou tenta ate 'tentativas' if (fase(f, senha[f]) == 0) break; ok = ok + 1; // passou mais uma }; if (ok != senhas) continue; // outra tentativa printf("\nPORTA LIBERADA!\n\n"); return 0; }; printf("\nTente outra vez. Encerrando!...\n\n"); return 0; }; int fase(int etapa, int alvo) { int numero = -1; printf("[Etapa %d de 5] Digite o numero: ", 1 + etapa); scanf("%d", &numero); if (numero != alvo) return 0; printf("voce passou pela etapa %d! Continue...\n\n", 1 + etapa); return 1; }; int fase1(int etapa, int alvo) { int numero = -1; printf("[Etapa %d de 5] Digite o numero: ", 1 + etapa); scanf("%d", &numero); while (numero != alvo) { printf("\nVoce digitou um numero incorreto!\n"); printf("Tente novamente\n\n"); printf("[Etapa %d de 5] Digite o numero: ", etapa); scanf("%d", &numero); }; if (numero != alvo) return 0; printf("voce passou pela etapa %d! Continue...\n\n", 1 + etapa); return 1; }; fase1() era o exemplo original, que não retorna enquanto o cara não acertar um valor... Copie com cuidado e não mexa na ordem das coisas.
  13. Não, não é. Veja a própria mensagem de erro do seu próprio programa em dois compiladores de amplo uso: nome_comodo é um ponteiro constante para uma área onde residem permanentemente 30 char. É diferente. É difícil par um iniciante às vezes entender isso. Nem sei se é o seu caso, mas sei que não entendeu. nome_comodo é um ponteiro e aponta para uma região permanentemente alocada de 30 bytes. Veja o que dizem os compiladores: char(*)[30]. É muito diferente de um ponteiro para char. Postou um exemplo que sequer compila e não parece levar a nada. "Exatamente" o que? adicionado 7 minutos depois Não. O valor de um ponteiro é sempre um endereço. Pode ser de outro ponteiro se for um ponteiro para um outro ponteiro, e aí seria o "endereço de outra variável", que por sua vez poderia ser "o endereço de outra variável", como char*** referencias; que eu já usei umas vezes para catalogar referências a textos. Não há limite para isso. Mas é rara a necessidade. Como todo programa em C começa por main() e main() sempre recebe um ponteiro para um ponteiro, não se pode dizer que é incomum um ponteiro apontar para um ponteiro, já que o protótipo de main() é int main(int, char**); não é? adicionado 21 minutos depois Sim, mas não é necessariamente um char*. Isso é importante de se entender. Pode ser const, pode ser char(*)[]... Veja os exemplos que mostrei. E o seu próprio exemplo.
  14. Pense bem nisso: se quer ganhar experiência nessa linguagem ou alguma outra não deveria estar usando um compilador configurado para a versão de 1998 Acha mesmo que não vai te fazer falta? Que nada importante mudou nesses anos todos? Pois é: se tem algo de que vai precisar para estudar ou aprender nessa área é exatamente isso. Paciência. E ler muito. Qual o ambiente que usa pra compilar, o IDE --- sim, IDE é masculino --- e a versão? Sabe ver isso? O mais comum que vejo aqui nesse forum é Code::Blocks e a versão atual acho que é 17.12. Tem um outro comum que vejo aqui que é o Dev-C++ e a versão acho que é 5.11. Você não conseguiu acrescentar uma única opção? Algo simples como nesse Dev-C++ ou nesse outro Code::Blocks, por exemplo Ou isso no caso da Microsoft
  15. Sim. Em C ou C++ uma cadeia de char é uma sequência de bytes, terminada por um 0, o tal NULL, o '\0'. Isso de um ponto de vista lógico. Em termos de memória, de alocação, uma string ou vetor é determinada (o) por um nome, e um comprimento. O nome corresponde a um ponteiro para o início e é um ponteiro como outro qualquer. O comprimento é outra parada. Veja esses casos const char* valor = "teste"; char* outro_c = "outro"; char coisa[20]; char* vetor = (char*)malloc(30); const char* pc; char* outroP; const char* const pConst = coisa; Os ponteiros para char são ponteiros e tem o tamanho de todos os ponteiros, em geral 4 bytes. Mas a área alocada é um problema a determinar. No caso de vetor oficialmente não dá pra saber. Está claro que são 30 aí mas o que você pode fazer com essa área é liberar os 30 (sem saber quantos são), realocar para algum outro valor, mesmo que sejam 30 de novo (e talvez mudando o endereço). Não dá pra saber o tamanho. coisa é formalmente como p, um const char*. Mas p não aponta para nada e sequer foi inicializado. pConst veio para ficar: aponta fixamente para um endereço fixo A questão de scanf() não foi bem descrita. Formalmente o fato é que scanf() não aloca memória: é preciso passar o endereço de uma área de memória previamente alocada. Usar & para passar o endereço de algo para scanf() é apenas fornecer o que a função espera. Como um vetor é identificado pelo início, scanf() se contentaria com coisa ou com pc porque são apontadores para uma área. valor não serviria porque é const, mas outro_c serviria mas vai cancelar o programa... Em resumo: é preciso dançar conforme a música. @Mauro Britivaldo Não dá pra entender que "afirmação difundida na literatura" você estaria questionando, e seu exemplo tem erros básicos. Não há nada demais em questionar a literatura. Autores erram e mesmo normas ISO são revistas por erros. Mas acho que deveria explicar o que está questionando e qual o seu argumento ao invés de difundir coisas assim Seu "exemplo prático" Note que matriz sequer é um ponteiro para char, apesar de apontar para um. Seu compilador deve ter te dito isso nas mensagens de erro. Leia abaixo. Veja que na linha 10 seu programa já tem dois erros bobos e sequer compilaria, porque faltam os parenteses nos dois sizeof(). Não seria um alerta, apenas um erro. Dois erros. E a linha 7 poderia gerar um alerta dependendo das opções de compilação: qual o propósito de atribuir um valor a ponteiro_de_ponteiro na linha 7 e outro na linha 8? ponteiro_de_ponteiro = &ponteiro; // ??? vai ser sobreposto na linha seguinte ponteiro_de_ponteiro = &matriz; // ??? matriz é char(*)[30] e ponteiro é char** Poderia ter escrito milhares de linhas assim e apenas a última atribuição iria sobreviver. Não sei que compilador usa, e não sei as opções de compilação que usa para compilar isso --- /W0 talvez? --- mas a atribuição na linha 8 deve gerar erro, um warning, um alerta. No gcc 8.2 Ou no CL 19.26 E pode aproveitar para ler que matriz não é um pointer para char simplesmente, ao menos segundo o gcc e o CL e o ANSI C e eu. Corrigindo o seu programa #include <stdio.h> int main(void){ char matriz[30]; char* ponteiro; char** ponteiro_de_ponteiro; ponteiro_de_ponteiro = &matriz; printf("M: %u == P: %u \n", sizeof(matriz), sizeof(ponteiro)); return 0; } Matriz é do tipo char[30]; Foi declarada estaticamente. Então quanto acha que sizeof(matriz) vai retornar? Sem surpresas, 30. E ponteiro_de_ponteiro foi declarado char**. Quanto acha que sizeof() vai retornar? Sem surpresas, vai retornar 4 ou 8 porque ponteiro_de_ponteiro é um ponteiro, assim como ponteiro e o tamanho dele é... sizeof(int*) por exemplo, já que hoje em dia os ponteiros tem o mesmo tamanho para qualquer tipo. Tanto faz para onde aponte. sizeof() é só um operador. Um ponteiro é só um ponteiro. Entendendo sizeof() Acrescentando uma outra chamada a printf() em seu programa e corrigindo os erros #include <stdio.h> int main(void){ char matriz[30]; char* ponteiro; char** ponteiro_de_ponteiro; ponteiro_de_ponteiro = (char**) matriz; printf("M: %u == P: %u \n", sizeof(matriz), sizeof(ponteiro)); printf("M: %u == P: %u\n", sizeof(char[30]), sizeof(char**)); return 0; } Você vai ver Sim, dá na mesma. Não faz diferença para sizeof() Se escrever ponteiro_de_ponteiro = (char**)matriz; printf("M: %u == P: %u \n", sizeof(matriz), sizeof(ponteiro)); ponteiro_de_ponteiro = 28; printf("M: %u == P: %u \n", sizeof(matriz), sizeof(ponteiro)); ponteiro_de_ponteiro = NULL; printf("M: %u == P: %u \n", sizeof(matriz), sizeof(ponteiro)); printf("M: %u == P: %u\n", sizeof(char[30]), sizeof(char**)); Vai ver Porque dá na mesma. A menos que compile para 64 bits quando vai ter Sem surpresas. Onde quer chegar? Seu "exemplo prático" uma vez corrigido diz o que em relação à literatura?
  16. No geral as funções que manipulam caracteres estão em ctypes.h. Tem uma tabela em https://www.tutorialspoint.com/c_standard_library/ctype_h.htm
  17. Sim. Pode reescrever strcmp() ou mesmo ver a tal roda feita como está em https://code.woboq.org/userspace/glibc/string/strncmp.c.html Mas é só um loop mesmo.
  18. Precisa realmente disso? Se não faz parte do enunciado passe um filtro no txt e deixe apenas as letras. Isso é um inferno e não tem fim. E não acrescenta nada ao software de locadora e ao algoritmo em si. Mas se precisa mesmo disso defina a página de código em uso para uma que tenha essas letras, como a 850 ou 65001 usando SetConsoleOutputCP(850) por exemplo como descrita em https://en.wikipedia.org/wiki/Code_page_850 O certo é usar no início do programa GetConsoleOutputCP(void); e salvar o valor. Aí você chama SetConsoleOutputCP(850) e ao final do programa restaura chamando o que salvou, como int pagina = GetConsoleOutputCP(void); SetConsoleOutputCP(850); ... SetConsoleOutputCP(pagina); // ao final Deve ser só isso.
  19. Sim. Está certo. No geral isso se chama Algebra de Boole. No particular está é uma propriedade da igualdade: decorre de duas coisas iguais a uma terceira serem iguais entre si: a propriedade transitiva da igualdade. A igualdade também é simétrica e reflexiva. Essas 3 relações definem a igualdade: uma coisa é igual a ela mesma (reflexiva) se A é igual a B B é igual a A para todo A (simétrica) duas coisas iguais a uma terceira são iguais entre si (transitiva) E dessa última decorre aprova daquele troço de && e || Sobre a parada de maiúsculas/minúsculas eis um pedaço da tabela ASCII onde tem os códigos das letras e você vê que a diferença é sempre 32. As minúsculas são menores porque no início não havia minúsculas. Durante muito tempo os computadores e impressoras só tinhas maiúsculas e por isso elas vieram antes e depois foram aumentando os códigos para 128 e depois 256 e hoje estão em 1.1 milhão de símbolos na tabela Unicode 32 é o bit 5 então você pode converter uma letra para minúscula fazendo letra = letra | 32; ou fazendo a conta mesmo, somando 32. O contrário claro também é verdade. Mas no seu caso teria que fazer isso com TODAS as letras, cero? um loop como faz strcmp() adicionado 3 minutos depois É uma classe, e você pode declarar variáveis dessa classe. São chamadas instâncias em C++ string nome_comodo; e até poderia acessar a string do jeito C usando nome_comodo.c_str(); o que é chamado método da classe string. Um deles.
  20. Você tem de fato formação na área de Teoria da Informação? Computação? Isso que eu disse formalmente É a verdade, a definição da linguagem. Já leu um standard? Tem um livro em que acredite? Qual seria? Escreveu algum? Não é assim porque eu acho e você não. Creio que a nomenclatura em português é dereferenciado numa herança do termo em inglês dereference. Um ponterio dereferenciado "tecnicamente" é do tipo da variável a que ele aponta. É a definição. Um ponteiro dereferenciado só será um ponteiro em casos como o clássico char** argv onde *argv é um pointer para char. Apenas quando o ponterio aponta para um ponteiro. E (**argv) é, pela mesma definição, um char. Pela mesma razão argv[1] é do tipo char*, e argv[1][0] é um char, a primeira letra do nome completo de um programa em C ou C++. De modo bem similar em Pascal ou java ou Algol60. Sequer existe uma definição de matriz nessas linguagens. Isso é apenas aceito a partir do uso acadêmico do termo matriz por matemáticos --- no caso a partir dos vetores multidimensionais em FORTRAN no início dos '60 --- e se entende que uma matriz seria um array com mais de uma dimensão. Isso sequer existe em C, onde o que seria uma matriz de duas dimensões é ou um vetor de vetores ou um bloco contínuo e uma fórmula de associação. Veja por exemplo a definição: Do clássico "Estruturas de Dados Usando C" - de Aaron Ai Tenenbaum, Yedidyah Langsam, e Moshe J. Augenstein editado em português pela Makkron Books Isso que escreveu está de fato além da minha compreensão ou não faz sentido mesmo. Recomendo muito que estude antes de postar essas coisas. Linguagens são coisas absolutamente formais e descritas em padrões rígidos. Não basta achar que algo é assim ou ter uma forte opinião. Existe um padrão,. um standard como o draft do standard de C ISO 9899 o último padrão eu não tenho, custa $198. Mas esse é um draft e serve bem para o que quero dizer. É legal ter opiniões controversas e tal, mas tem coisas que simplesmente são definidas a partir de rígidos padrões. Por favor não poste essas coisas sem referência ou embasamento apenas dizendo que são fatos ou que tecnicamente é isso e pronto. É apenas mais uma versão de fake news.
  21. Na verdade não. O determinante é a declaração: char nome_comodo[30]; Tanto em C quanto em C++. nome_comodo é um ponteiro para char, e assim *nome_comodo é um char. E é o que temos. Em C++ tem a classe string e a classe string_view, e a aí você pode comparar diretamente strings porque nelas o operador '==' foi redefinido e para essa classe ele incorpora a funcionalidade de strcmp() de varrer a string até o '\0' e ir comparando. Para comparar assim em C++ teria que declarar nome_comodo como string e rever o resto do programa. nome_comodo é um ponteiro para char e só pode ser comparado com outro ponteiro para char, em C ou C++. Exemplo (em C++ ou C) char nome_comodo[30] = { "teste" }; // [1] char* pChar = nome_comodo; char* outrop = NULL; if (pChar == nome_comodo) if (outrop == pChar) *(pChar + 1) = 'E'; Em C++ o igual em [1] é opcional e não recomendado. Está aqui exatamente pela razão que faz ele existir: portabilidade com código em C. Veja aí que nome_comodo vale "teste". Mas você só pode fazer comparações como essas aí. Comparando com outros ponteiros para char. O código não faz sentido: é um exemplo que digitei no meio de meu programa Essa deveria ir para o forum de lógica. Porque não funciona: duas coisas diferentes não podem ser iguais a uma terceira. A terceira coisa aqui seria o valor zero. Se a condição A for verdade a condição B será falsa e se a condição A for falsa a condição B poderá ser verdade, e assim ( A ou B ) será sempre verdade... Acompanhe: se nome_comodo for "fim" a primeira é falsa e a segunda é verdadeira e então a expressão A ou B é verdade se nome_comodo for "FIM" a primeira é verdadeira e a segunda é falsa, então a expressão A ou B é verdade se nome_comodo não for nem "fim" nem "FIM" as duas condições A e B são verdade e a expressão (A ou B ) é verdade A outra condição, A e B verdadeiro é impossível, como eu disse no início Então a expressão escrita assim é sempre verdadeira e o while() nunca termina...
  22. Muito bem! Bom que conseguiu. int fase(int etapa, int alvo) { int numero = -1; printf("[Etapa %d de 5] Digite o numero: ", 1 + etapa); scanf("%d", &numero); if (numero != alvo) return 0; printf("voce passou pela etapa %d! Continue...\n\n", 1 + etapa); return 1; }; Resolveu não seguir o caminho de usar uma função como no exemplo?
  23. Use a própria tabela que postou como um gabarito. Em geral é assim que se faz em relatórios multi-coluna Veja como pode ser fácil: 0 * 1 * 2 * 3 * 3 0123456789012345678901234567890123456789 Vetor A Vetor B 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789012345678901234567890123456789 0 * 1 * 2 * 3 * 3 Digite no próprio IDE. Veja aqui em cima com um grid com os números das colunas... Cada número vai ter no máximo 10 dígitos, certo? Lá estão eles. O espaço entre as colunas pode ser de 4 bytes. Já sabe o que imprimir em cada linha. Na tabela você vê as colunas e o resto é trivial. DICA importante: use sprintf() e formatar as linhas fica um passeio Na família printf() tem fprintf() que imprime em um arquivo e sptrintf() que imprime em uma variável, um vetor de char que você pode usar para montar a linha. TODAS essas funções retornam o tamanho da saída em bytes. Em geral ninguém lê ou usa isso. Mas tem hora que é salvador. Ou útil ao menos. Exemplo int coluna[4] = { 1'000'000'123, 2'000'000'234, 1'000'000'123, 2'000'000'234 }; char espaco = ' '; char linha[80]; int col = sprintf(linha, "%10d%4c%10d\n", coluna[0], espaco, coluna[1]); printf("colunas em uso: %d\n", col); for(int i=0;i<5;i+=1) printf("%s", linha); Você ajusta as posições lado a lado para tantas colunas quanto precise, e sprintf() monta a linha em linha. O 10 em %10d indica que vai usar 10 posições para o valor, e pra não ter que ficar contando espaços que não da pra ver na linha usa %4c para imprimir a variável que tem um espaço usando 4 posições e assim alinha a segunda coluna. No gabarito dá pra ver que a segunda coluna termina na posição 23 então com o '\n' para pular de linha serão 25 (começa de 0) e não custa nada fazer o computador trabalhar e mostrar o retorno de sprintf() pra ver se está dando 25.. Depois apagamos. Aí fica fácil. Só de ler o sprintf() e somar 10+10+4 já sabe que vai imprimir 24 colunas e olhando o gabarito vê que a linha está terminando na coluna 23 --- a partir de 0 --- e então sabe que está certo. E se protege para o futuro: se tivesse 4 colunas e você for separar duas a duas com mais espaço no meio escreveria sprintf(linha, "%10d%4c%10d%8c%10d%4c%10d\n", coluna[0], espaco, coluna[1], espaco, coluna[2], espaco, coluna[3]); for (int i = 0; i < 5; i += 1) printf("%s", linha); usando a mesma variável espaco E imprime no for 5 linhas de cada só pra ver se está bom... Eis um trecho de código graças ao control-c control-v int col = sprintf(linha, "%10d%4c%10d\n", coluna[0], espaco, coluna[1]); printf("colunas em uso: %d\n", col); for(int i=0;i<5;i+=1) printf("%s", linha); sprintf(linha, "%10d%4c%10d%8c%10d%4c%10d\n", coluna[0], espaco, coluna[1], espaco, coluna[2], espaco, coluna[3]); for (int i = 0; i < 5; i += 1) printf("%s", linha); Que mostra colunas em uso: 25 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 1000000123 2000000234 Espero que tenha entendido a ideia: monta a linha em linha[] no programa e depois mostra com printf() normal usando só o %s... Esse é um conceito importante para as 3 ou 4 pessoas que imprimem relatórios complexos em C hoje em dia
  24. Sugiro escrever dois programas para não misturar as coisas Faça um programa simples para ficar lendo e gravando uns 10 int no arquivo até se entender com seek() e tratar o arquivo Para os dados escreva um programa em torno dos dados, uma struct{} com os valores pedidos. NÃO escreva um menu. Apenas use umas constantes, 2 ou 3 valores já serão suficientes para você fazer o programa e testar todas as funções. Implemente cada recurso em uma função separada, sem ler nada do teclado e sem gravar nada no disco Depois junte o que fez no primeiro programa, trocando os int pela struct. Depois que estiver certo de que nada está se perdendo entre ler e gravar no disco escreva o simples menu. uma função que retorna a opção. E já que aprendeu a ler do arquivo no primeiro programa, leia o menu do arquivo assim você pode digitar o menu no próprio IDE porque é um p*$$e ficar alinhando texto e opções de menu
  25. Faça como na segunda opção que eu mostrei

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...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!