• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Ribamar

[Resolvido] Problema com stdin

37 mensagens neste tópico

Boas

Estou a ter problemas com o seguinte:

Tenho um metodo que remove espaços repetidos numa string.

Quando eu tenho:

int main(){
char* a ="  abcfs     sadasdasd";
puts(norepspaces(a));
return 0;
}

o programa corre sem problemas.

mas se eu quiser ler do input uma linha, estou a fazer o seguinte:

int main(){
char a[51];
fgets(a,50,stdin);
puts(norepspaces(a));
return 0;
}

e assim tem comportamento esquisito, porque se eu inserir a string " a   b" o programa remove os espaços ficando a string "a b", agora se eu inserir qq que seja a string que tenha 6 ou mais caracteres o programa da erro windows "program has stopped working".

estou desesparado, ja n sei o q fazer, alguem tem alguma ideia de porque isto acontece? é que so da erro qd leio do stdin, se eu criar uma string nem que tenha 1000 caracteres o programa não da erro...

cumps

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Coloca aqui a função norepspaces.

E já agora, experimenta testar com uma string que tenha um '\n' no fim.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
char* norepspaces(char* s){
char* ptr1 = s;
char* ptr2 = s;
int flag = 0;
while(*ptr1 == ' '){
	++ptr1;
	flag = 1;
}
while(*ptr1 != '\0'){
	if(flag == 0){
		while(*ptr1 != ' ' && *ptr1 != '\0'){
			++ptr1;
			++ptr2;
		}
		++ptr1;
	}
	else{
		while(*ptr1 != ' ' && *ptr1){
			*ptr2 = *ptr1;
			++ptr1;
			++ptr2;
		}
		++ptr1;
	}
	if(*ptr1 == ' '){
		while(*ptr1 == ' ' && *ptr1){
			++ptr1;
			flag = 1;
		}
	}
	if(flag == 1){
		*ptr2 = ' ';
		++ptr2;
	}
}
*ptr2 = '\0';
return s;
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Problema 1)

char *a = "    asd    fdsa";
/* devia ser */
const char *b = "    asdf    fdsa";

As string literais constantes não são necessariamente alteráveis (no meu computador tentar alterar a dá-me "Segmentation Fault", tentar alterar b dá-me erro de compilação)

Vou estudar o resto do teu código para outros (possíveis) problemas.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não sei se o código está correcto (agora não estou com muita paciência para o testar), mas aqui corre sem problemas.

Já agora, podias simplificar um pouco a função :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

corre sem problemas? mesmo qd escreves no input uma string c mais de 5 catacteres? vou testar noutro pc...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
rcg @ ~ > prog

add    fe f e f  efaefafa    d ds  as

add fe f e f efaefafa d ds as

rcg @ ~ > prog

dada wdwa

dada wdwa

rcg @ ~ > prog

a  a  a

a a a

rcg @ ~ > prog

  hh    hh   

hh hh

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

char* norepspaces(char* s){
char* ptr1 = s;
char* ptr2 = s;
int flag = 0;
while(*ptr1 == ' '){
	++ptr1;
	flag = 1;
}
while(*ptr1 != '\0'){
	if(flag == 0){
		while(*ptr1 != ' ' && *ptr1 != '\0'){
			++ptr1;
			++ptr2;
		}
                        /* O ERRO ESTÁ AQUI! XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
		++ptr1; /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
	}
	else{
		while(*ptr1 != ' ' && *ptr1){
			*ptr2 = *ptr1;
			++ptr1;
			++ptr2;
		}
                        /* O ERRO ESTÁ AQUI! XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
		++ptr1; /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
	}
	if(*ptr1 == ' '){
		while(*ptr1 == ' ' && *ptr1){
			++ptr1;
			flag = 1;
		}
	}
	if(flag == 1){
		*ptr2 = ' ';
		++ptr2;
	}
}
*ptr2 = '\0';
return s;
}

Quando chegas ao fim da string (*ptr1 == '\0') acrescentas 1 ao ptr1.

Na instrução imediatamente a seguir testas se o conteúdo de ptr1 (o char a seguir ao '\0' que pode até não fazer da string) é um espaço: pode ser, pode não ser, pode dar erro, pode formatar-te o disco, pode fazer o que lhe apetecer ...

Além disso, nunca metes o flag a 0 ... não estudei o código suficientemente a fundo para saber se isso é importante ou não, mas parece-me esquisito :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

a flag é para controlar se ha espaços a remover numa string, ou seja, se meteres uma string que n tenhas espaços a mais o programa nao vai andar a copiar caracteres para o mesmo sitio, pois isso n faz sentido. so a partir do momento em que ha 1 espaço a mais, e consequentemente os ponteiros deixam de apontar para o mesmo caracter, é que faz sentido copiar caracteres, e foi por isso que usei a flag

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tendo em conta que estás a devolver a string, se calhar depois usar uma nova string.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Vou tentar fazer o prog usando uma string auxiliar onde vai ficar a string final sem espaço. penso que ira ser mais facil e usar menos codigo. eu tentei fazer so com a string original para poupar espaço ao nao ser preciso criar nova string, mas torna-se mais complexo em termos de aritmetica de ponteiros

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mesmo com a mesma string, conseguia simplificar isso. E não precisas de andar com apontadores, podes trabalhar com índices de arrays.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
#include <stdio.h>
#include <string.h>

        char* norepspaces(char* str){
char* ptr1 = str, *ptr2 = str;
while(*ptr1 == ' ') ++ptr1;
while(*ptr1){
	while(*ptr1 != ' ' && *ptr1){
		*ptr2 = *ptr1;
		++ptr1;
		++ptr2;
	}
	if(*ptr1 != '\0'){
		*ptr2 = ' ';
		++ptr2;
	}
	while(*ptr1 == ' ' && *ptr1) ++ptr1;
}
*ptr2 = '\0';
return str;
}

int main(){
char* a ="          csda   sad basds   ";
puts(norepspaces(a));
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Boa Ribamar!

A tua função ainda tem um bugzito: se meteres uma string que comece por espaços (como no exemplo da função main()), esses espaços iniciais desaparecem completamente em vez de se transformarem num único espaço.

Para corrigires esse bugzito basta remover a primeira instrução da função norepspaces() (a linha com while(*ptr1 == ' ') ++ptr1;).

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

mas é assim que deve funcionar... qual é o interesse de uma frase começar com um espaço?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Ah! Ok, então não tens bug ... mas o comentário não dizia isso

E qual é o interesse duma frase acabar com um espaço? :cheesygrin:

O interesse duma frase começar (ou acabar) com um espaço depende da aplicação.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Pois....

No cod que tenho se a string introduzida tiver espaços no fim, ele deixa la ficar 1... que se lixe, ja perdi demasiado tempo com este programa.

E tens razao, dependo do contexto na aplicação onde é usado o método se é para deixar um espaço no inicio/fim.

cumps e obrigado pelas dicas

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

A minha função é muito parecida com a tua.

Só está um bocadinho mais compacta ...

#include <assert.h>
char *pmg_norepspaces(char *dst, const char *src) {
  char *bk = dst;
  assert(src);
  while (*src == ' ') src++;                 /* ignore leading spaces */
  while (*src) {
    if (*src != ' ') *dst++ = *src++;                    /* copy char */
    else {
#if 0
      while ((*src == ' ') && (*src)) src++;           /* skip spaces */
#endif
      while (*src == ' ') src++;                    /* JJ skip spaces */
      if (*src) *dst++ = ' ';    /* add space if not at end of string */
    }
  }
  *dst = 0;                                        /* 'terminate' dst */
  return bk;
}

Podes chamá-la com o dst == src para ter o mesmo efeito que a tua função

/* #includes */
int main(void) {
  char teste[] = "    foo    bar    ";
  printf("%s\n", pmg_norepspaces(teste, teste));
  return 0;
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Explica la o assert que nao sei o que é :cheesygrin:

a tua esta mais compacta mas em termos de custo é praticamente = à minha.

por exemplo onde eu uso

*ptr2 = *ptr1;
++ptr1;
++ptr2;

tu usas

*dst++ = *src++;

o numero de operações é o mesmo, O(n)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

while ((*src == ' ') && (*src))

Não li o código com muita atenção, mas a(s) guarda(s) daquele(s) while(s) está/ão redundante(s). Se (*src == ' '), então também vamos ter (*src). Por outro lado, se (*src == ' ') for falsa, nunca vamos chegar a verificar a segunda condição.

JJ

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Explica la o assert que nao sei o que é :cheesygrin:

assert é uma macro que fica inactiva quando compilas com o simbolo NDEBUG definido.

Quando está inactiva é o mesmo que não ter lá nada.

Quando está activa, ela testa a condição e se for falsa imprime uma mensagem em stderr e aborta o programa.

Se a condição for verdadeira não faz nada.

Atenção nunca usar assert() com condições que têm efeito secundário: esse efeito secundário só é visível quando o programa está compilado para debug.

#include <assert.h>
/* ... */
assert(i++ == j); /* OOPS */

a tua esta mais compacta mas em termos de custo é praticamente = à minha.

Sim, as duas funções são muito parecidas.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

while ((*src == ' ') && (*src))

[...] a(s) guarda(s) daquele(s) while(s) está/ão redundante(s) [...]

Obrigado JJ, alterei o código na minha mensagem.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

#if 0
      while ((*src == ' ') && (*src)) src++;           /* skip spaces */
#endif

o que é isso do #if?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Atenção nunca usar assert() com condições que têm efeito secundário: esse efeito secundário só é visível quando o programa está compilado para debug.

Isso é importante. A macro é um bocado tosca, porque podia ter sido programada de modo a o efeito lateral ser sempre visível. Por outro lado, normalmente só precisamos de usar "funções puras" dentro das assertions.

Eu acho que não devemos meter asserts à toa no meio do código. Normalmente prefiro usá-los no início das funções que tratam de ADTs para testar pré-condições (por exemplo, um StackPop pode ter uma assertion para verificar que o stack não está vazio), e por vezes no fim.

Isto faz sentido, porque supostamente o caller devia ter chamado manualmente um StackEmpty antes de fazer StackPop, ou calcular de outra maneira qualquer que este tinha chegado ao fim.

JJ

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora