Pergunta

Eu tenho que correr em algum código e queria saber o que o desenvolvedor original estava fazendo. Abaixo é um programa simplificado usando este padrão:

      #include <stdio.h>

      int main()  {     

      char title[80] = "mytitle";      
      char title2[80] = "mayataiatale";      
      char mystring[80]; 

      /* hugh ? */
      sscanf(title,"%[^a]",mystring);
      printf("%s\n",mystring); /* Output is "mytitle" */


      /* hugh ? */
      sscanf(title2,"%[^a]",mystring); /* Output is "m" */
      printf("%s\n",mystring);


      return 0;  
  }

O href="https://linux.die.net/man/3/scanf" rel="nofollow noreferrer"> página homem tem informações relevantes, mas estou tendo problemas lê-lo. Qual é o propósito de usar este tipo de notação? O que é que está tentando realizar?

Foi útil?

Solução

A principal razão para as classes de personagens é para que a notação% s pára no primeiro caractere espaço em branco, mesmo se você especificar comprimentos de campo, e você muitas vezes não quer que ele. Nesse caso, a notação classe de personagem pode ser extremamente útil.

Considere este código para ler uma linha de até 10 caracteres, descartando qualquer excesso, mas mantendo espaços:

#include <ctype.h>
#include <stdio.h>

int main(void)
{
    char buffer[10+1] = "";
    int rc;
    while ((rc = scanf("%10[^\n]%*[^\n]", buffer)) >= 0)
    {
            int c = getchar();
            printf("rc = %d\n", rc);
            if (rc >= 0)
                    printf("buffer = <<%s>>\n", buffer);
            buffer[0] = '\0';
    }
    printf("rc = %d\n", rc);
    return(0);
}

Este foi realmente exemplo de código para uma discussão sobre comp.lang.c.moderated (cerca de junho de 2004) relacionada com getline() variantes.


Pelo menos alguns reina a confusão. O primeiro especificador formato, %10[^\n], lê-se a 10 caracteres não nova linha e eles são atribuídos para tamponar, juntamente com um nulo de arrasto. O segundo formato de especificador, %*[^\n] contém o carácter de supressão de atribuição (*) e lê zero ou mais restantes caracteres não nova linha a partir da entrada. Quando a função scanf() concluída, a entrada está apontando para o próximo caractere de nova linha. O corpo do loop lê e imprime esse personagem, de modo que quando o laço for reiniciado, a entrada é olhar para o início da próxima linha. O processo então repete. Se a linha é menor do que 10 caracteres, em seguida, os caracteres são copiados para o buffer, eo 'zero ou mais não-newlines' processos formato zero não novas linhas.

Outras dicas

As construções como %[a] e exist %[^a] para que scanf() podem ser usados ??como uma espécie de analisador léxico. Estes são uma espécie de como %s, mas em vez de recolher um período de quantos caracteres "stringy" quanto possível, eles coletam apenas uma extensão de personagens como descrito pela classe de personagem. Pode haver casos em que a escrita %[a-zA-Z0-9] pode fazer sentido, mas eu não tenho certeza se eu ver um caso de uso atraente para aulas complementares com scanf().

IMHO, scanf() simplesmente não é a ferramenta certa para este trabalho. Toda vez que eu tenho a intenção de usar um de seus recursos mais poderosos, eu acabei eventualmente, rasgando-o para fora e implementar a capacidade de uma maneira diferente. Em alguns casos, isso significava usar lex para escrever um analisador léxico real, mas geralmente fazendo linha de cada vez I / O e quebrando-o grosseiramente em tokens com strtok() antes de fazer a conversão valor foi suficiente.

Editar: Acabei arrancando scanf() normalmente porque quando confrontados com os usuários insistindo no fornecimento de entrada incorreta, ele simplesmente não é bom em ajudar o feedback bom programa dar sobre o problema, e ter um montador imprimir "Erro, encerrado." como única mensagem de erro útil não estava indo muito bem com o meu usuário. (Me, nesse caso.)

É como conjuntos de caracteres de expressões regulares; [0-9] corresponde a uma seqüência de dígitos, [^aeiou] corresponde a qualquer coisa que não seja uma vogal minúsculas, etc.

Há todos os tipos de usos, tais como puxando para fora números, identificadores, pedaços de espaço em branco, etc.

Você pode ler sobre isso no ISO / padrão IEC9899 disponível online.

Aqui está uma citação parágrafo I do documento sobre [ (página 286):

corresponde a uma seqüência não-vazia de caracteres a partir de um conjunto de espera caracteres.

O especificador de conversão inclui todos os caracteres subsequentes no string de formato, até e incluindo o suporte direito correspondente (]). o caracteres entre os suportes (a ScanList) compor o scanset, a menos que o caractere após o colchete esquerdo é um circunflexo (^), em que caso o scanset contém todos os caracteres que não aparecem no a lista de varredura entre o circunflexo e o suporte direito. Se o especificador de conversão começa com [] ou [^], o suporte direito personagem é na lista de varredura eo imediatamente seguinte colchete direito personagem é o suporte direito correspondente que termina a especificação; caso contrário a primeira seguinte caractere de colchete direito é aquele que termina a especificação. Se a - personagem está na lista de varredura e não é o primeiro, nem o segundo onde o primeiro caractere é a ^, nem o último caractere, o comportamento é definido pela implementação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top