2010-04-29 15 views
8

Aquí está el código:¿Cómo determinar el final de una matriz de enteros al manipular con un puntero entero?

int myInt[] ={ 1, 2, 3, 4, 5 }; 
int *myIntPtr = &myInt[0]; 
while(*myIntPtr != NULL) 
{ 
    cout<<*myIntPtr<<endl; 
    myIntPtr++; 
} 

Output: 12345....<junks>.......... 

Para matriz de caracteres: (Ya que tenemos un carácter nulo al final, no hay problema, mientras que la iteración)

char myChar[] ={ 'A', 'B', 'C', 'D', 'E', '\0' }; 
char *myCharPtr = &myChar[0]; 
while(*myCharPtr != NULL) 
{ 
    cout<<*myCharPtr<<endl; 
    myCharPtr++; 
} 

Output: ABCDE 

Mi pregunta es, ya decimos para añadir NULL carácter como final de las cadenas, ¡descartamos tales problemas! Si en el caso, es una regla para agregar 0 al final de la matriz de enteros, podríamos haber evitado este problema. ¿Que dice?

Respuesta

10

La convención C-strings es un acabado char * con un carácter '\ 0'. Para array o cualquier otro contenedor de C++, existen otros modismos que se pueden aplicar.A continuación sigue mis preferencias

La mejor manera de iterar en secuencias es utilizar el basado en la gama de bucle incluido en C++ 0x

int my_array[] = {1, 2, 3, 4, 5}; 
for(int& x : my_array) 
{ 
    cout<<x<<endl; 
} 

Si el compilador no proporciona esta aún, utilizar iteradores

for(int* it = std::begin(array); it!=std::end(array); ++it) 
{ 
    cout<<*it<<endl; 
} 

Y si no se puede usar ni std :: iniciar/finalizar

for(int* it = &array[0]; it!=&array[sizeof(array)]; ++it) 
{ 
    cout<<*it<<endl; 
} 

Boost PS. Foreach emula el bucle for para Range en los compiladores C++ 98

+0

¿Dónde se define std :: begin/end? ¿Viene con C++ 0x? –

+0

@Christian: Sí, o con Boost. – UncleBens

+0

@Christian Sí, esta es una nueva característica de C++ relacionada con Range. Boost.Range incluye esto y mucho más, simplificando mucho el algoritmo en las secuencias. –

11

En C++, la mejor solución es utilizar un std :: vector, no una matriz. los vectores llevan su tamaño alrededor con ellos. El problema con el uso de cero (o cualquier otro valor) como marcador final es que, por supuesto, no puede aparecer en ningún otro lugar de la matriz. Esto no es un problema tanto para las cadenas, ya que rara vez queremos imprimir el carácter con el código cero, pero es un problema cuando se utilizan matrices de entradas.

+0

Estoy de acuerdo con el uso de std :: vector aquí. Una pregunta general que tengo. ¿Cómo en los vectores, son capaces de determinar el tamaño de la matriz de enteros? – AKN

+0

@AKN Llevan el tamaño como un valor separado de algún tipo. –

+0

@AKN std: vector no es solo una matriz, es probablemente una estructura que contiene una matriz y una int para longitud y posiblemente más. – phkahler

3

Sin duda, puede decidir por su cuenta "sentinel" value para almacenar al final de su matriz de números enteros. Si siempre se espera que sus enteros sean no negativos, por ejemplo, puede usar -1 como el valor centinela que marca el final de la matriz.

int myInt[] ={ 1, 2, 3, 4, 5, -1 }; 
int *myIntPtr = &myInt[0]; 
while(*myIntPtr >= 0) 
{ 
    cout<<*myIntPtr<<endl; 
    myIntPtr++; 
} 
1

El valor de char 0 tiene un significado especial, estandarizado por convención y práctica. El valor int 0 no, por lo que esta no puede ser una regla general. Si funciona en su caso específico, puede hacerlo. Sin embargo, en general, es mejor realizar un seguimiento de la longitud de las matrices de enteros por separado, ya que esto funciona universalmente. O use std::vector o un contenedor similar que maneje ese trabajo por usted.

0

Use std :: vector, como dice Neil.

O hacerlo de la manera iterador:

int myInt[] ={ 100, 200, 300, 400, 500 }; 
int *myIntPtr = &myInt[0]; 
int *myIntPtr_end = myIntPtr + 5; 
while(myIntPtr != myIntPtr_end) 
    { 
    cout<<*myIntPtr<<endl; 
    ++myIntPtr; 
    } 
+0

Aquí vemos '5' y, por supuesto, esa es la longitud que podemos usar directamente ¡a la derecha! :) – AKN

+0

int * myIntPtr_end = myIntPtr + 5; El puntero * myIntPtr_end apunta a SOME_JUNK_VALUE después del último valor. (es decir) después de 500. Dado que para este defecto de diseño, siento que no es aconsejable. ¿Que dice? – AKN

+0

No importa que esté apuntando a basura, siempre y cuando no desreferencia el puntero. En cuanto a la longitud de la matriz, obviamente la tiene disponible en su ejemplo. Si está hablando de punteros a matrices sin información sobre la longitud, eso es algo que debe agregar a su pregunta/descripción. –

3
+0

Porque no existe tal cosa, estás pensando en sizeof. y esto no se puede usar una vez que la matriz se haya descompuesto en un puntero. –

+0

@Neil Butterworth gracias, eso fue solo un caso agudo de dislexia :) Sin embargo, no se dice nada acerca de no poder acceder a la matriz. Esto también se puede usar para implementar algo así como la clase de plantilla de matriz de comprobación de límites. –

0
for(i=0; i < sizeof(myInt); i++) 
{ 
    cout<<*myIntPtr<<endl; 
    myIntPtr++; 
} 

Si estás sugiriendo que su código donde se manipula myIntPtr no tiene ni idea del tamaño del fragmento que hace referencia, que o bien tienen que decidir por un valor mágico de la matriz de int o reestructurar su código para que sizeof(myInt) también está disponible.

Las funciones de la biblioteca estándar C utilizan el último enfoque: siempre que necesite pasar un área de memoria intermedia por un puntero, debe pasar su tamaño en la misma llamada.

+1

Gracias kostas. Pero sizeof (myInt) no dará directamente el tamaño de la matriz. Entonces, en su lugar, se puede cambiar a 'int nIntArrSize = sizeof (myInt)/sizeof (int)' – AKN

1

En primer lugar, no "agregamos caracteres NULL" al final de la cadena. No existe el "carácter NULL". Agregamos cero carácter, que a veces se denomina "carácter NUL". Pero NULL no tiene absolutamente nada que ver con eso. NULL se usa normalmente en el contexto del puntero y no en el contexto de caracteres o enteros. Sus comparaciones como *myCharPtr != NULL o *myIntPtr != NULL se compilarán (debido a la forma en que se define NULL en C++), pero prácticamente no tienen sentido. Si busca un carácter cero en una matriz, puede verificarlo como *myCharPtr != '\0' o como *myCharPtr != 0 o simplemente como *myCharPtr, pero nunca como *myCharPtr != NULL.

En segundo lugar, el carácter cero se llama carácter cero por una razón: es igual a cero entero. El tipo de carácter en C++ es simplemente un tipo entero simple después de todo. La única razón por la que podemos usar carácter cero como algo especial en el contexto de cadena es porque su significado está reservado para ese propósito específico. En general, en el contexto de enteros, reservar cero para ese propósito es claramente imposible por razones obvias: cero es tan útil como cualquier otro valor entero. Sin embargo, si en su aplicación específica, el número cero puede usarse como un valor reservado, siéntase libre de usarlo de esa manera. O puede usar cualquier otro valor entero para ese propósito. Pero en el caso general, refiriéndose a la pregunta que hace en el título, hay de ninguna manera para determinar el final de una matriz. Es su responsabilidad saber dónde está el final (conociendo el número total de elementos o marcando el final con un valor reservado de su elección o de alguna otra manera). No hay forma de determinar el final de una matriz incluso con cadenas, porque todo lo que puede esperar es encontrar el final de la cadena , que no es necesariamente el final de la matriz que almacena esa cadena.

Si agregó explícitamente un cero al final de su matriz de enteros, su primer ciclo se detendría felizmente. Por alguna razón, agregó explícitamente \0 al final de su matriz de caracteres (y el segundo ciclo se detiene), pero no agregó un cero al final de su matriz de enteros (y el primer ciclo no se detiene). ¿Te estás preguntando por qué tu primer ciclo no se detuvo en cero? Porque no pusiste ese cero ahí. Es así de simple.

1

Tanto el estándar ASCII como el Unicode definen un carácter con el valor 0 como el carácter NULL, no como un marcador de final de serie/cadena. Es solo la convención C/C++ que las cadenas terminan con este caracter. Pascal usa una notación diferente. Además, el carácter NULL no indica necesariamente el final de la matriz que contiene la cadena. Hay varias funciones de la API de Win32 que utilizar el doble terminada en nulo cuerdas (el diálogo de archivo abierto para uno), así:

"one\0two\0three\0" // there's an implicit '\0' appended in C/C++ 

Esto es válido el código C/C++, el carácter nulo no significa que el final de la matriz .

Para adaptar esta idea de un valor NULO a matrices enteras, significa que debe sacrificar uno de sus valores enteros. Si sus datos consisten en un subconjunto del conjunto de enteros, entonces esto no es un problema, pero si sus datos pueden consistir en cualquier valor entero, entonces no hay manera de determinar si un entero dado es el marcador de fin de matriz o un valor válido En este último caso, necesita información adicional sobre la cantidad de elementos en la matriz, ya sea de forma manual o automática a través de std :: vector.

0

La forma genérica de crear el puntero final para cualquier matriz es la siguiente: Primero determine la cantidad de elementos en la matriz usando sizeof(array)/sizeof(array[0]). Tenga en cuenta que sizeof aparece dos veces porque devuelve el tamaño de un elemento en bytes. Entonces, para una matriz estática, este es el tamaño de la matriz dividido por el tamaño de un elemento en la matriz. Entonces, el puntero a una matriz es array+number_of_elements. Así que esto debería funcionar:

int myInt[]={1, 2, 3, 4, 5}; 
int myIntNumElements = sizeof(myInt)/sizeof(myInt[0]); 
int *myIntEnd = myInt + myIntNumElelents; 

for (int *myIntPtr = myInt; myInt != myIntEnd; myIntPtr++) 
    { 
    cout << *myIntPtr << endl; 
    } 

Y ahora para algunas advertencias:

puntero apunta
  • el final para un lugar justo después del final de la matriz! Entonces, *myIntPtr devuelve basura, no el valor del último elemento en la matriz.
  • ¡Esto solo es bueno para arreglos regulares y estáticos! Para contenedores, use las funciones e iteradores de miembros begin y end.
  • Este enfoque funcionará con cualquier versión de C++. Sin embargo, si usted está usando C++ - 11 o posterior, es recomendable utilizar las funciones std::begin y std::end en la sentencia for de la siguiente manera:

    for (int *myIntPtr = std::begin(myInt); myIntPtr != std::end(myIntPtr); myIntPtr++)

  • Este método está destinado a ser considerados, además de la Otras respuestas. Cuál es el mejor es una cuestión de contexto.

Cuestiones relacionadas