2010-01-22 20 views
9

Pregunta para principiantes sobre la eficiencia de bucle. Empecé a programar en C++ (mi primer idioma) y he estado usando 'Principios y práctica usando C++' de Bjarne Stroustrup. He recorrido los primeros capítulos y me acabo de presentar el concepto de bucles.Eficiencia de bucle - C++

El primer ejercicio relacionado con los bucles me pide lo siguiente: El caracter 'b' es char ('a' + 1), 'c' es char ('a' + 2), etc. Use un ciclo para escribir una tabla de caracteres con sus valores enteros correspondientes:

un 97, b 98, ..., z 122

Aunque, solía mayúsculas, creé la siguiente:

int number = 64; //integer value for @ sign, character before A 
char letter = number;//converts integer to char value 
int i = 0; 

while (i<=25){ 
    cout << ++letter << "\t" << ++number << endl; 
    ++i; 
    } 

¿Debo aspirar a tener solo 'i' estar presente en un bucle o simplemente no es t posible al convertir entre tipos? No puedo pensar de ninguna otra manera en que lo anterior se pueda hacer aparte de convertir el valor del personaje en su contraparte entera (es decir, opuesto al método actual) o simplemente no tener la conversión y tener el almacén de letras '@'.

+0

Gracias por los chicos de aclaración, me da la vuelta hacia adelante unas pocas páginas y se pide para reconstruirlo usando un ciclo for =). – SlackerByNature

+1

ahh, los métodos maestros se vuelven claros –

Respuesta

9

Debería apuntar primero a la claridad y en su lugar tratar de optimizar la micro optimización. Se podría volver a escribir mejor que como un bucle for:

const int offsetToA = 65; 
const int numberOfCharacters = 26; 
for(int i = 0; i < numberOfCharacters; ++i) { 
    const int characterValue = i + offsetToA; 
    cout << static_cast<char>(characterValue ) << characterValue << endl; 
} 

y se puede convertir entre diferentes tipos - eso se llama fundición (el constructo static_cast en el código anterior).

+6

Sobre el tema de la claridad; Las constantes numéricas rara vez son una buena idea. Propongo que se asigne a 'offsetToA' el valor' 'a'' (o '' A''), que se convierte implícitamente en (el correcto)' int'. Por supuesto, esto también requiere que el primer carácter impreso se calcule como 'offsetToA + 0'. –

2

no hay nada particularmente ineficiente en la forma en que lo hace, pero ciertamente es posible simplemente convertir entre caracteres y caracteres (un carácter es un entero). esto significa que solo necesita almacenar 1 contador en lugar del 3 (i, letra + número) que actualmente tiene

también, para pasar de un inicio fijo a un ciclo 'para' es quizás más idiomático (aunque su posible usted no ha conocido a esto todavía)

2

Eso no es una mala manera de hacerlo, pero se puede hacer con una sola variable de bucle como este:

char letter = 65; 

while(letter <= 65+25){ 
    printf("%c\t%d\n", letter, letter); 
    ++letter; 
} 
22

raíz de jk incluso se podría utilizar el carta en sí misma en el ciclo (letra < = 'z'). También usaría un ciclo for, pero así soy yo.

for(char letter = 'a'; letter <= 'z'; ++letter) 
    std::cout << letter << "\t" << static_cast<int>(letter) << std::endl; 
+0

Correcto: en realidad itera sobre las _letters_! +1 para programar lo más cerca posible de _intention_. – xtofl

+0

¿Pero garantiza C++ que ''a '+ 1 ==' b''? También vea mi respuesta a esta pregunta para más detalles. –

+2

@Alok: la experiencia garantiza que 'a' + 1 == b. Tan pronto como trabaje en un entorno en el que no lo haga, escribiré el código que trata con él;) – Patrick

0

Incrementar tres variables por separado es probablemente un poco confuso. Aquí hay una posibilidad:

for (int i = 0; i != 26; ++i) 
{ 
    int chr = 'a' + i; 
    std::cout << static_cast<char>(chr) << ":\t" << chr << std::endl; 
} 

Tenga en cuenta que el uso de un bucle for mantiene toda la lógica de montar, comprobar e incrementando la variable de bucle en un solo lugar.

0

En este punto, no me preocuparían las micro optimizaciones, como una forma eficiente de escribir un pequeño bucle como este. Lo que tiene permite un bucle for para hacer bien el trabajo, pero si está más cómodo con while, debe usarlo. Pero no estoy seguro si esa es su pregunta.

No creo que haya entendido la pregunta correctamente. Está escribiendo el código, sabiendo que 'A' es 65. El objetivo del ejercicio es imprimir el valor de 'A' en 'Z' en su sistema, sin saber qué valor tienen.Para obtener un valor entero para un carácter c, puede hacer: static_cast<int>(c). Creo que eso es lo que estás preguntando.

No he escrito ningún código porque debería ser más divertido para usted.

pregunta para los expertos: En C, sé que 'a' ... 'z' no necesita tener valores continuos (lo mismo para 'A' ... 'Z'). ¿Es lo mismo para C++? Creo que sí, pero parece muy poco probable que el libro de Stroustrup asuma eso.

+0

Puedo entender su punto, pero realmente es tan básico como lo que escribí, static_cast (c) no se ha presentado, el lector nunca está al tanto de tales posibilidades. Dio un ejemplo anterior de crear una lista de números y sus cuadrados a través de un bucle. Se trata más de simplemente presentar la idea de un bucle, no el contenido de un bucle. Si eso tiene sentido. – SlackerByNature

+0

Alok: no, no creo que C++ lo garantice tampoco. Los juegos de caracteres de origen y ejecución se definen en 2.2, que establece que los dígitos decimales son consecutivos pero no mencionan letras. Pero el que pregunta dice que está en un texto que me parece copiado de la pregunta en el libro. Así que creo que, a los fines de la pregunta, Bjarne está diciendo que las letras minúsculas son consecutivas. Como dice slackerbyname, no se trata de manejar EDCBIC, ni de cómo y cómo introducir restricciones de puertos a su código ... –

+0

"para obtener un valor entero para un carácter c, puede hacer:' static_cast (c) ' ". O 'int i = c;', que es lo que esperaría. –

2

Si usted está preocupado por la eficiencia de su bucle, me animo a probar este:

obtener este código compilado y se ejecuta en un entorno de desarrollo, como Visual Studio, y establecer un punto de interrupción al principio . Cuando llegue allí, cambie a la vista de desmontaje (vista de instrucciones) y comience a presionar la tecla F11 (paso único), y lleve un recuento mental de cuántas veces la está golpeando.

Verá que entra en el ciclo, compara i contra 25, y luego comienza a hacer el código para la línea cout. Eso implica incrementar letter, y luego pasar a la rutina << para cout. Hace una serie de cosas allí, posiblemente profundizando en subrutinas, etc., y finalmente vuelve a salir, devolviendo un objeto. A continuación, presiona "\t" como argumento y lo pasa a ese objeto, vuelve a entrar y hace todo lo que hizo antes. Luego toma number, lo incrementa y lo pasa a la rutina cout::<< que acepta un entero, llama a una función para convertirlo en una cadena (que involucra un bucle), luego hace todo lo que hizo antes para enlazar esa cadena en el salida buffer y return.

¿Cansado? Aún no has terminado. El endl tiene que salir, y cuando eso sucede, no solo pone "\n" en el búfer, sino que llama a la rutina del sistema para vaciar ese búfer al archivo o consola donde está enviando la E/S. Probablemente no pueda usar F11, pero tenga la seguridad de que requiere muchos ciclos y no regresa hasta que se complete la E/S.

Por ahora, su conteo de F11 debe estar cerca de varios miles, más o menos.

Finalmente, sales y llegas a la instrucción ++i, que toma 1 o 2 instrucciones, y salta al principio del ciclo para comenzar la siguiente iteración.

AHORA, ¿todavía le preocupa la eficiencia del circuito?


Hay una manera más fácil de hacer esto, y es igual de instructivo. Envuelve un ciclo infinito alrededor de todo tu código para que funcione para siempre. Mientras se está ejecutando, presiona el botón "pausa" en el IDE y mira la pila de llamadas. (This is called a "stackshot".) Si haces esto varias veces, tienes una buena idea de cómo pasa el tiempo. He aquí un ejemplo:

NTDLL! 7c90e514() 
KERNEL32! 7c81cbfe() 
KERNEL32! 7c81cc75() 
KERNEL32! 7c81cc89() 
MSVCRTD! 1021bed3() 
MSVCRTD! 1021bd59() 
MSVCRTD! 10218833() 
MSVCRTD! 1023a500() 
std::_Fputc() line 42 + 18 bytes 
std::basic_filebuf<char,std::char_traits<char> >::overflow() line 108 + 25 bytes 
std::basic_streambuf<char,std::char_traits<char> >::sputc() line 85 + 94 bytes 
std::ostreambuf_iterator<char,std::char_traits<char> >::operator=() line 304 + 24 bytes 
std::num_put<char,std::ostreambuf_iterator<char,std::char_traits<char> > >::_Putc() line 633 + 32 bytes 
std::num_put<char,std::ostreambuf_iterator<char,std::char_traits<char> > >::_Iput() line 615 + 25 bytes 
std::num_put<char,std::ostreambuf_iterator<char,std::char_traits<char> > >::do_put() line 481 + 71 bytes 
std::num_put<char,std::ostreambuf_iterator<char,std::char_traits<char> > >::put() line 444 + 44 bytes 
std::basic_ostream<char,std::char_traits<char> >::operator<<() line 115 + 114 bytes 
main() line 43 + 96 bytes 
mainCRTStartup() line 338 + 17 bytes 

lo hice un montón de veces, y no una vez que se detenga en el código para el bucle externo i<=25. Así que optimizar ese ciclo es como la gran metáfora de alguien: "cortarse el pelo para perder peso".

1

Dado que nadie más lo mencionó: Teniendo una cantidad fija de iteraciones, este también es un candidato para la iteración post-condición con do..while.

char letter = 'a'; 
do { 
    std::cout << letter << "\t" << static_cast<int>(letter) << std::endl; 
} while (++letter <= 'z'); 

Sin embargo, como se muestra en la Patrick's answerfor modismo es a menudo más corta (en número de líneas en este caso).

0

gracias por la ayuda .. todo lo escrito era

int main() 
{ 
char letter = 96; 
int number = letter; 
int i = 0; 

while(i <26) 
{ 
cout <<++letter <<":" <<++numbers <<" "; 
++i; 
} 

funciona muy bien ... y bastante sencillo de entender ahora.

1

Puede promover char a int ...

//characters and their corresponding integer values 
#include"../../std_lib_facilities.h" 

int main() 
{ 
    char a = 'a'; 
    while(a<='z'){ 
     cout<<a<<'\t'<<a*1<<'\n'; //a*1 => char operand promoted to integer! 
     ++a; 
    } 

    cout<<endl; 
} 
0

He intentado esto y funcionó bien:

char a = 'a'; 
int i = a; //represent char a as an int 
while (a <= 'z') { 
cout << a << '\t' << i << '\n'; 
++a; 
++i; 
}