Bruno_F Posted October 20, 2007 at 12:58 PM Report Share #141574 Posted October 20, 2007 at 12:58 PM Estou agora a começar a tirar a minha licenciatura em Eng. Informática.. e consequentemente estou a começar a aprender C (já tinha umas noções ?). O que se passa é que ao fazer os códigos no meu computador, usando o Dev-C++ 4, acontece que ao ler uma variável (p.e um numero inteiro) através de um scanf, ao imprimi-la no ecrã ela dá um numero completamente diferente. Um exemplo: #include <stdio.h> #include <stdlib.h> int main() { int d; scanf("%d", &d); printf("%d", &d); system("PAUSE"); return 0; } Neste (muito) simples programa, é suposto introduzir-se um num, e o programa reproduzi-lo de seguida. Só que ao corre-lo o numero que eu insiro não corresponde ao numero imprimido. Por exemplo ponho um 4 e aparece um 32894850. Se me pudessem ajudar agradecia. Cumprimentos Link to comment Share on other sites More sharing options...
Hipnoted Posted October 20, 2007 at 01:07 PM Report Share #141576 Posted October 20, 2007 at 01:07 PM Dá um valor estranho porque estás a tentar mostrar o endereço da posição de memória da variável d. Tens de meter o printf sem o &. printf("%d", d); "Nunca discutas com um idiota. Eles arrastam-te até ao seu nível e depois ganham-te em experiência" Link to comment Share on other sites More sharing options...
Bruno_F Posted October 20, 2007 at 01:57 PM Author Report Share #141590 Posted October 20, 2007 at 01:57 PM ok já dá... obrigado pela ajuda. Isto de ser noob a programação tem que se lhe diga. ? Já agora uma outra duvida diferente: Num exercício tenho que fazer um programa que leia um horario em formato 24horas e o transforme num 12horas. P.e 21.40 fica 9.40 PM. A solução que eu encontrei foi: #include <stdio.h> #include <stdlib.h> int main() { int hora; int hora2; int min; scanf("%d", &hora); scanf("%d", &min); if (hora>12) { hora2=hora-12; printf("São %d horas e %d minutos PM", hora2, min); } else if (hora==12) { hora2=hora; printf("São %d horas e %d minutos PM", hora2, min); } else if (hora==0) { hora2=12; printf("São %d horas e %d minutos AM", hora2, min); } else { hora2=hora; printf("São %d horas e %d minutos AM", hora2, min); } system("PAUSE"); return 0; } O programa funciona... mas a minha ideia inicial era: int main() { int hora, hora2, min; char ampm[2]; scanf("%d", &hora); scanf("%d", &min); if (hora>12) { hora2=hora-12; ampm= "PM" } else if (hora==12) { hora2=hora; ampm= "PM" } else if (hora==0) { hora2=12; ampm= "AM" } else { hora2=hora; ampm= "AM" } printf("São %d horas e %d minutos, %c", hora2, min, ampm); system("PAUSE"); return 0; } Só que tive de abandonar esta ideia visto que ao compilar o programa dava erro. Depois de pesquisar percebi que era por causa dos ampm= "AM", já que não se pode atribuir assim valores a strigs. A minha dúvida é: haverá alguma maneira de atribuir um valor a uma string sem ser lida pelo teclado? Ou seja dizer que a string A é igual a "ABC", por exemplo? Mais uma vez obrigado pela resposta, e desculpem as perguntas de noob ? PS: Ainda não dei vectores, e consequentemente não dei strings Link to comment Share on other sites More sharing options...
Hipnoted Posted October 20, 2007 at 02:00 PM Report Share #141592 Posted October 20, 2007 at 02:00 PM Para copiar uma string tens de usar o strcpy. No teu caso ficaria: strcpy(ampm, "PM"); "Nunca discutas com um idiota. Eles arrastam-te até ao seu nível e depois ganham-te em experiência" Link to comment Share on other sites More sharing options...
garmg Posted October 22, 2007 at 12:02 AM Report Share #142022 Posted October 22, 2007 at 12:02 AM Para copiar uma string tens de usar o strcpy. No teu caso ficaria: strcpy(ampm, "PM"); Deve ser realçado que não é boa prática, utilizar o strcpy num array. Quanto muito deve-se utilizar o strncpy (ou strlcpy) para evitar falhas de segurança. Neste caso, o uso do strcpy vai causar um problema, uma vez que a variável tem apenas 2 bytes e o strcpy termina sempre a string destino com um null ('\0'), o que significa que o array ampm[] vai passar a ter este tipo de dados em memória no caso de um strcpy(ampm, "PM"): ampm[0] = 'P' ampm[1] = 'M' ampm[2] = '\0' Só que, o índice 2, não foi assegurado na definição do array porque esta foi definida com o tamanho de 2 bytes. O que acontece é que, a variável min do programa do bruno_f, vai ser subscrita no byte mais à direita (arquitecturas little endian) pelo \0 do strcpy, alterando o valor da mesma. No caso acima, não causa propriamente uma falha de segurança, uma vez que o valor "PM" está hard-coded, mas se o 2º argumento do strcpy fosse manipulável por um utilizador, este poderia ganhar controlo sobre o fluxo do programa! No entanto, pode decorrer inconsistência dos dados (especialmente os que estiverem relativos à variável min) e umas boas dores de cabeça quando o programa estoirar sem motivo aparente. 1 exemplo simples para ilustrar o cenário corrente: int main() { int n = 1; char foo[2]; strcpy(foo, "PM"); printf("%d %s\n", n, foo); printf("%08x (foo[2]) == %08x (n)\n", &foo[2], &n); } 0 PM bff22934 (foo[2]) == bff22934 (n) Era esperado que a variável n fosse mostrada com o valor 1, mas o strcpy, ao escrever na variável foo (análoga à ampm do programa do bruno_f) guarda o \0 na memória subjacente, neste caso, como estou (e assumo que a maioria das pessoas neste forum também está) numa arquitectura little endian, em que a memória stack é gerida de cima para baixo (em termos de endereçamento) o \0 é escrito no endereço inferior, neste caso, na var seguinte (ou anterior, por definição -- para quem está a olhar para o código em top-down). Se repararem, no fim, eu faço o print do endereço da variavel 'n' e do índice 2 do array foo. Alguns devem-se questionar como tou a aceder ao índice 2, se a variavel está definida com apenas 2 elementos no array. Como a memória stack funciona como uma sequencia de bytes, aquele indice, aponta para o byte no endereço de memória inferior, neste caso, aponta para o 1º byte dos 4 bytes alocados pelo inteiro 'n'. Espero que tenha sido útil, e espero não ter dito muita gralha... a estas horas já devia estar a dormir :-) EDIT: Para melhor informação sobre como a memória stack funciona, sugere-se a leitura do artigo sobre o desenvolvimento de exploits na edição 6# da Revista Programar que, embora não tenha lido na totalidade, faz uma introdução à forma de como a memória é gerida nas arquitecturas x86 e mostra como se pode tirar partido de certos erros na gestão da mesma. 10 Useful Links Link to comment Share on other sites More sharing options...
TheDark Posted October 22, 2007 at 12:42 AM Report Share #142024 Posted October 22, 2007 at 12:42 AM Não é boa prática, não. O strncpy introduz uma perda de performance em relação à strcpy por causa de (pelo menos) mais um decremento e mais uma verificação. Pode parecer pouco, mas em programas em que a velocidade é crítica e a função utilizada repetidamente pode provocar lentidão na execução. Se aconselhas a sua utilização, tudo bem, apoiado. Mas dizeres que não é boa prática penso que é exagerado. Ena rimei... Desaparecido. Link to comment Share on other sites More sharing options...
garmg Posted October 22, 2007 at 01:40 AM Report Share #142030 Posted October 22, 2007 at 01:40 AM A segurança assenta grande parte das vezes em compromissos de usabilidade e performance. Escolhe as tuas prioridades (Não deixas de ter a tua quota-parte de razão, atenção! ;-) 10 Useful Links Link to comment Share on other sites More sharing options...
Hipnoted Posted October 22, 2007 at 08:46 AM Report Share #142044 Posted October 22, 2007 at 08:46 AM Não é boa prática quando o programador não aloca espaço suficiente para copiar a string para o array. Eu uso sempre o strcpy, claro que ao primeiro cheguei a cometer erros como os que referiste mas acho que um bom programador de C tem de prevenir essas coisas, e até há coisas bem piores de gerir como deves saber. 🙂 "Nunca discutas com um idiota. Eles arrastam-te até ao seu nível e depois ganham-te em experiência" Link to comment Share on other sites More sharing options...
Warrior Posted October 22, 2007 at 09:36 AM Report Share #142047 Posted October 22, 2007 at 09:36 AM Isto está a entrar um pouco em off-topic, mas a questão aqui não é se se deve ou não usar o strcpy, é saber se o programador sabe o que está a fazer ou nem por isso. Neste caso, aumentar o tamanho do array era suficiente, uma vez que o utilizador não tem qualquer hipótese de adulterar o que vai ser colocado lá. Contudo, e fundamentalmente em leituras, o cuidado que temos que ter é enorme. Nós não sabemos quantos caracteres o leitor vai inserir. Nunca. Logo, usar "scanf("%s",s);" é um erro enorme. Depois de ler a string de modo "correcto" (com fgets) o strcpy deixa de ser tão perigoso. Basta ter o cuidado de a string de entrada e a string de saída terem o mesmo tamanho (pode ser particularmente difícil se alocarmos dinamicamente a memória, mas isso é um caso especial). Link to comment Share on other sites More sharing options...
garmg Posted October 22, 2007 at 11:11 AM Report Share #142059 Posted October 22, 2007 at 11:11 AM Não é boa prática quando o programador não aloca espaço suficiente para copiar a string para o array. Eu uso sempre o strcpy, claro que ao primeiro cheguei a cometer erros como os que referiste mas acho que um bom programador de C tem de prevenir essas coisas, e até há coisas bem piores de gerir como deves saber. 🙂 Só fiz a nota porque, ao indicares a um utilizador para utilizar a função strcpy no corrente cenário, estavas a incitar más práticas de programação. Acredito que tenham sido causadas por falta de atenção porém, ainda assim, serviu-me como exercício de memória, pra ver até que ponto ainda me lembrava de C :-) 10 Useful Links Link to comment Share on other sites More sharing options...
Gurzi Posted October 22, 2007 at 11:50 AM Report Share #142062 Posted October 22, 2007 at 11:50 AM Só não percebi isto printf("%08x (foo[2]) == %08x (n)\n", &foo[2], &n); que cena marada o que é o %08x Link to comment Share on other sites More sharing options...
garmg Posted October 22, 2007 at 11:52 AM Report Share #142063 Posted October 22, 2007 at 11:52 AM faz print do valor alinhado a 8 dígitos hexadecimais, neste caso, faz print de um endereço 32 bit em hexadecimal. 10 Useful Links Link to comment Share on other sites More sharing options...
Triton Posted October 22, 2007 at 12:03 PM Report Share #142065 Posted October 22, 2007 at 12:03 PM faz print do valor alinhado a 8 dígitos hexadecimais, neste caso, faz print de um endereço 32 bit em hexadecimal. Já agora, é mais correcto usar o especificador %p para a escrita de endereços de ponteiros. <3 life Link to comment Share on other sites More sharing options...
Gurzi Posted October 22, 2007 at 12:19 PM Report Share #142071 Posted October 22, 2007 at 12:19 PM Que conclusões conseguem tirar vendo o valor em hexadecimal ? :X Link to comment Share on other sites More sharing options...
Triton Posted October 22, 2007 at 01:12 PM Report Share #142075 Posted October 22, 2007 at 01:12 PM Que conclusões conseguem tirar vendo o valor em hexadecimal ? :X Os endereços de memória costumam-se representar em notação hexadecimal. E consegues perceber que &foo[2] == &n. 🙂 Atenção que isto não se verifica em todas as situações, por exemplo nesta máquina os valores não coincidem. 1 PM 0xbf9ed754 (foo[2]) == 0xbf9ed74c (n) Aborted (core dumped) Mas o que o garmg disse continua a estar correcto, é preciso ter cuidado com o que se faz. 🙂 <3 life Link to comment Share on other sites More sharing options...
garmg Posted October 22, 2007 at 02:05 PM Report Share #142086 Posted October 22, 2007 at 02:05 PM Que conclusões conseguem tirar vendo o valor em hexadecimal ? :X Os endereços de memória costumam-se representar em notação hexadecimal. E consegues perceber que &foo[2] == &n. 🙂 Atenção que isto não se verifica em todas as situações, por exemplo nesta máquina os valores não coincidem. 1 PM 0xbf9ed754 (foo[2]) == 0xbf9ed74c (n) Aborted (core dumped) Mas o que o garmg, é preciso ter cuidado com o que se faz. 🙂 Isso deve-se à forma como o gcc 4.x ou eventuais patches de segurança que alteram o alinhamento das variaveis na stack na compilação. Eu testei aquele exemplo acima no gcc do RHEL 4. No RHEL5 os valores diferem da mesma forma. Aqui têm mais alguma informação que ajuda a entender a parte do alinhamento da stack e como funcionam as protecções contra stack overflows que compiladores adicionam ao binário final: http://www.phrack.org/issues.html?issue=56&id=5 EDIT: Quanto às conclusões que se podem tirar: identificar se é um endereço de stack ou heap/bss. 10 Useful Links Link to comment Share on other sites More sharing options...
Bruno_F Posted October 22, 2007 at 07:40 PM Author Report Share #142185 Posted October 22, 2007 at 07:40 PM Mais uma vez obrigado pelas ajudas e esclarecimentos adicionais... o programa já funciona da maneira que eu quero. 🙂 :) Quanto ao problema levantado pelo garmg, também me deparei com o facto de os minutos estarem a dar valores indevidos, por isso declarei a variável ampm como uma array char[3], não sei se é a solução mais indicada mas para já tem funcionado. Cumps Link to comment Share on other sites More sharing options...
TheDark Posted October 22, 2007 at 09:45 PM Report Share #142269 Posted October 22, 2007 at 09:45 PM É exactamente o indicado 😉 Queres guardar 2 caracteres -> alocas 3 (ou mais) posições no array. Mas não esqueças toda a conversa sobre segurança do código que o teu post originou! Quando não tiveres a certeza da dimensão da string que vais copiar, utiliza o strncpy. Claro que, como bom programador, o teu trabalho é descobrir o tamanho 😄 Desaparecido. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now