Pruebas de software para el progtwig de contar palabras en un flujo de caracteres

He hecho un progtwig donde la entrada dada debe ser una secuencia de caracteres y el progtwig cuenta los caracteres y palabras que no son espacios en blanco. palabra se define como la secuencia de caracteres que están separados por un carácter de espacio en blanco. Así que aquí está el progtwig …

#include  #include #include  #include int main(void) { unsigned long int wordcount = 0,charcount = 0, count=1; int ch; bool flag, prev; while ((ch = getchar()) != EOF) { if(isgraph(ch)) flag=true; else flag=false; if(flag) charcount++; if(count ==1) prev = flag; if(count != 1) { if(prev and (not flag)) wordcount++; prev = flag; } count++; } if((ch == EOF) and flag) wordcount++; printf("\nnumber of words counted are %lu \n", wordcount); printf("\nnumber of characters counted are %lu \n", charcount); return 0; } 

Ahora he comprobado este progtwig en oraciones simples. Pero solo para practicar, quiero hacer pruebas detalladas de software sobre esto. Entonces, ¿cómo puedo hacer eso? ¿Acabo de dar más cantidad de oraciones? Intenté dar algunos párrafos de algunas novelas que encontré en el proyecto Gutenberg. ¿Qué más puedo hacer aquí? ¿También puedo mejorar la eficiencia de este progtwig?

Hay varias pruebas básicas para hacer:

  1. Archivo vacío
  2. Archivo con un solo espacio en blanco
  3. Archivo con un solo no en blanco
  4. Archivo con un espacio en blanco y uno no en blanco
  5. Archivo con uno no en blanco y otro en blanco
  6. Archivo con varios espacios en blanco solamente
  7. Archivo solo con varios espacios en blanco
  8. Archivo con varios espacios en blanco seguidos de espacios en blanco.

Y así continúa … esto es la prueba de límites; asegurándose de que el código funciona correctamente en condiciones de contorno.

Su asignación del valor de getchar() a un unsigned long int (ahora resuelto en la pregunta) es inusual. Debido a que el valor de retorno es positivo para un carácter regular y negativo (EOF) para el final del archivo o error, es normal asignarlo a un int llano firmado.

Su prueba ch == EOF después de que el bucle es redundante; La única forma de salir del bucle es cuando la condición es verdadera.

Usar y las palabras clave (macros) y not es inusual también.

Más comúnmente, las personas no colocan el código en la misma línea que la llave abierta de un bloque.

Podría incrementar el charcount en el bloque if donde estableció flag = true; . Podría usar un bloque else lugar de if (count != 1) . De hecho, AFAICT, su código:

 if(count ==1) prev = flag; if(count != 1) { if(prev and (not flag)) wordcount++; prev = flag; } 

podría ser escrito como:

 if (count > 1 and prev and (not flag)) wordcount++; prev = flag; 

La descripción ‘número de caracteres contados’ no es estrictamente precisa; es el número de caracteres gráficos (no en blanco, sin control) que está reportando. Probablemente esté en el extremo de hiper-nitpicking de la escala de inquietud, aunque (junto con la observación de que el ‘número de palabras’ es una cantidad singular y debería ser ‘es’ en lugar de ‘son’).

Es un poco inusual comenzar su count en 1 en lugar de cero. Parece registrar “uno más que el número de caracteres en bruto leídos en el progtwig”, que es una cantidad inusual para grabar. Más normalmente, también lo inicializaría en 0, y modificaría la prueba que reescribí para leer:

 if (count != 0 and prev and (not flag)) 

(Puede usar count != 0 o count > 0 ; para un valor sin signo, los términos son equivalentes.)

Es posible que pueda simplificar sus condicionales al inicializar prev (apropiadamente) como false .

Adquiera el hábito de poner la constante que está probando en la izquierda, como en

while (EOF! = (ch = getchar ()))

… ya que esto le ahorrará pasar incontables horas, justo cuando menos puede pagar un contratiempo, cuando escribe accidentalmente = cuando quiere decir ==. Como no puede asignar una variable a una constante, el comstackdor marcará su error y guardará su trasero.

En mi experiencia, una vez que te acostumbras a leer este tipo de código, encontrarás que es mucho más rápido encontrar lo que se está probando cuando está ubicado justo al lado del if (, while (, que buscarlo en algún lugar del cuerpo de La prueba. Esto es especialmente cierto si tiene una larga lista de pruebas, como abrir archivos, sockets, etc., y luego asignar memoria a través de malloc () para almacenar datos de archivos.

PD: Después de un examen, hay algunas cosas básicas de CS 101 que vale la pena mencionar …

Primero, tiene un caso clásico aquí, en este caso porque tiene el requisito de mirar detrás de un personaje, incluso en la primera pasada a través del ciclo while (), para sembrar un ciclo while (). La solución es configurar el bucle while () con un bloque simple if () que realice una sola pasada a través de la misma lógica que la del bucle while (). (FYI, a while () es un conjunto infinito de if () s con una condición de terminación)

La forma correcta de hacer esto es como se muestra. La recompensa es poder deshacerse de todas las pruebas if () de la operadora y verificar si esta es la primera vez que pasa por el ciclo while () cada vez que pasa por ese ciclo. El primer paso aquí se maneja con la prueba if () que precede al bucle while ().

Segundo, encontré que sus nombres de variables no son informativos. Eso no significa que estuvieran “equivocados”, pero es probable que alguien que intente mantener su código también tenga problemas. En mi experiencia, como usted entiende mejor un fragmento de código, los nombres de las variables mejoran y mejoran. Use eso como una prueba de fuego para saber si comprende el problema, tiene una buena solución y sabe por qué.

En tercer lugar, cuando se encuentra inicializando una variable en main () a 1, debería poner una marca en su mente sobre el control de flujo correcto, ya que lo que ahora es PassKnt era estar en 1. Además, generalmente, desea incrementar un contador de bucle en el FINAL del bucle / si / mientras, no el principio de éste. De nuevo, esto debería hacer que cuestione su lógica.

NOTA: Bloc de notas, de forma predeterminada, guarda en formato Unicode. Si usa el Bloc de notas para crear archivos de prueba para este progtwig, asegúrese de guardar en formato ANSI .

Lo dejé adentro, porque hace que el progtwig sea más fácil de entender, pero IsGraphFlg no es necesario aquí. En lugar de asignar IsGraphFlg a WasGraphFlg en la parte inferior del bucle, se puede hacer en la parte inferior de las mitades superior e inferior del bloque if-else, ya que los contextos suministran la misma información que IsGraphFlag.

  while (EOF != (ch = fgetc(pFile))) { if(isgraph(ch)) { IsGraphFlg=true; charcount++; } else { // this char is whitespace, last char was part of a word IsGraphFlg=false; if(WasGraphFlg) { wordcount++; } } WasGraphFlg = IsGraphFlg; PassKnt++; } 

También puede notar que PassKnt no tiene ningún propósito ahora, y ya no es necesario.

Se ha sugerido que isgraph () es óptimo, pero cuando creé una matriz bool y la inicialicé usando isgraph (), el código se ejecutó (sin un búfer de memoria, que es ~ 10X tan rápido como el de un archivo en este Dell XPS 8500 ) en poco menos de 2 / 3rds del tiempo: 9.25 relojes en lugar de 14.75 por personaje. Esta es una optimización completamente opcional, aunque significativa.

 bool IsGph[256]; for(i=0; i 

En uso, si (isgraph (i)) se reemplaza por if (IsGph [i]) en el bucle principal de conteo de caracteres y palabras.

Código actualizado 30/12/2012

 // Word_Counter.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "stdafx.h" #include  #include  #include  #include  #include  #define UCHAR unsigned char #define dbl double #define LLONG __int64 #define PROCESSOR_HZ ((LLONG) 3400000000) #pragma warning(disable : 4996) // // function prototypes FILE *OpenFiles (int *FileSz, char *FileName); // ----------------------------------------------------------------------- FILE *OpenFiles (int *FileSz, char *FileName) { FILE *pFile=NULL; if (NULL == (pFile = fopen ((char *)FileName, "r+t" ))) { printf ( "Can't open %s\n", FileName ); return NULL; } else { fseek(pFile,0,SEEK_END); *FileSz = ftell(pFile); rewind(pFile); printf("\nFile size is %i", *FileSz); return pFile; } } // ----------------------------------------------------------------------- int _tmain(int argc, char *argv[]) { bool IsGph[256]; UCHAR *p, *pBuff=NULL; int WrdKnt=0,CharKnt=0; int i, j, FileSz, LoopKnt=3500; time_t Etime=0,start=0, Eclocks=0; FILE *pFile=NULL; bool WasGraphFlg=false; // Initialize boolean array to detect printable characters for(i=0; i 

Si tiene problemas con el argumento de la línea de comando que especifica un nombre de archivo, en "Proyectos-> Propiedades-> Propiedades de configuración-> General" en Visual Studio, cambie "Unicode" al conjunto de caracteres "Multi-Byte" mal etiquetado. Siempre puede mirar la memoria de argv [1] en el depurador para averiguar qué hay realmente en argv [].