¿Cómo iterar sobre una cadena en C?

2 minutos de lectura

avatar de usuario
Vicente

Ahora mismo estoy intentando esto:

#include <stdio.h>

int main(int argc, char *argv[]) {

    if (argc != 3) {

        printf("Usage: %s %s sourcecode input", argv[0], argv[1]);
    }
    else {
        char source[] = "This is an example.";
        int i;

        for (i = 0; i < sizeof(source); i++) {

            printf("%c", source[i]);
        }
    }

    getchar();

    return 0;
}

Esto tampoco funciona:

char *source = "This is an example.";
int i;

for (i = 0; i < strlen(source); i++){

    printf("%c", source[i]);
}

me sale el error

Excepción no controlada en 0x5bf714cf (msvcr100d.dll) en Test.exe: 0xC0000005: Infracción de acceso al leer en la posición 0x00000054.

(traducido libremente del alemán)

Entonces, ¿qué tiene de malo mi código?

  • por favor, no edites el código que preguntaste. Eso cambia bastante su pregunta, por lo que muchas de las respuestas son irrelevantes. En su lugar, simplemente publique todas las cosas que ha intentado y mencione cuáles de ellas fueron en respuesta a las respuestas.

    – Michael Myers

    9 de julio de 2010 a las 15:13

  • La nueva prueba contra argc que agregó es incorrecta.

    luego

    9 de julio de 2010 a las 15:17

Usted quiere:

for (i = 0; i < strlen(source); i++) {

sizeof le da el tamaño del puntero, no la cadena. Sin embargo, hubiera funcionado si hubiera declarado el puntero como una matriz:

char source[] = "This is an example.";

pero si pasa la matriz a la función, eso también se convertirá en un puntero. Para cadenas, es mejor usar siempre strlen. Y tenga en cuenta lo que otros han dicho sobre cambiar printf para usar %c. Y también, teniendo en cuenta los comentarios de mmyers sobre la eficiencia, sería mejor mover la llamada a strlen fuera del ciclo:

int len = strlen(source);
for (i = 0; i < len; i++) {

o reescribir el bucle:

for (i = 0; source[i] != 0; i++) {

  • Uh, dudo un poco que quiera usar strlen como un límite. (Aunque concedido, en un programa de 10 líneas no hace mucha diferencia.)

    – Michael Myers

    9 de julio de 2010 a las 15:01


  • Bueno, la última vez que revisé, strlen tuvo que iterar a través de todos los caracteres para calcular la longitud. Y dado que char* podría cambiar en el bucle, el compilador no puede sacar el strlen fuera de los límites; eso hace que el ciclo sea O(n^2) en lugar de O(n). Por favor corrígeme si estoy equivocado.

    – Michael Myers

    9 de julio de 2010 a las 15:06

  • En este ejemplo, un buen compilador podría determinar que la cadena no cambia y omitir llamadas repetidas a strlen. Pero probablemente sea una mejor práctica almacenar la longitud en una variable antes del bucle.

    – R.. GitHub DEJA DE AYUDAR A ICE

    9 de julio de 2010 a las 15:09

  • @Neil Butterworth: La diferencia entre (i=0, max=strlen(str); i

    – Vatina

    9 de julio de 2010 a las 15:09

  • @anon Claro, no importa cuando se escribe un programa que imprime una cadena de 21 caracteres, pero la diferencia entre O (n ^ 2) y O (n) se hará muy evidente cuando importa.

    – El rocío de los elfos

    29 de abril de 2018 a las 18:05

avatar de usuario
alejandro c

Un modismo común es:

char* c = source;
while (*c) putchar(*c++);

Algunas notas:

  • En C, las cadenas son terminado en nulo. Itera mientras el carácter de lectura no es el carácter nulo.
  • *c++ incrementos c y devuelve el desreferenciado viejo valor de c.
  • printf("%s") imprime una cadena terminada en nulo, no un carácter. Esta es la causa de su violación de acceso.

  • Puedo usar while (*c++) putc(*c);?

    – Incerteza

    06/09/2014 a las 15:25

  • -1 “En C, las cadenas terminan en cero”. Esto no tiene sentido. Tal vez lo que estás tratando de decir es que las cadenas c deberían terminar en nulo.

    – Celeritas

    22 de septiembre de 2014 a las 4:06

  • @Celeritas: Encuentro el voto negativo un poco duro: C tiene soporte de idioma para cadenas terminadas en cero, y el OP las está usando. De acuerdo, puede usar cadenas contadas (p. BSTRs en el mundo de Windows), pero son menos comunes, y la pregunta no es ambigua en cuanto a qué tipo de cadena se está usando.

    – Alejandro C.

    22/09/2014 a las 18:20

  • Oh, ¿solo estás hablando de cómo se llaman? Zero-terminated es más bien un nombre del mundo de la API de Win32 (donde las variables de cadena tienen el prefijo estúpido de sz), y terminado en nulo es un nombre más “tradicional” (y común). De todos modos, ambos significan lo mismo.

    – Alejandro C.

    23/09/2014 a las 17:54

  • Es esto putc desde <stdio.h>? Porque parece que esa función espera un segundo argumento, un flujo. putchar se puede usar con un solo argumento como lo está haciendo este ejemplo.

    – Dave Yarwood

    02/09/2017 a las 14:30

avatar de usuario
marca ingram

En lugar de usar strlen como se sugirió anteriormente, puede verificar el carácter NULL:

#include <stdio.h>

int main(int argc, char *argv[])
{
    const char *const pszSource = "This is an example.";
    const char *pszChar = pszSource;

    while (pszChar != NULL && *pszChar != '\0')
    {
        printf("%s", *pszChar);
        ++pszChar;
    }

    getchar();

    return 0;
}

  • Funcionará, pero recomiendo comprobar pszChar != '\0' para ser explícito de todos modos. No estás comparando contra NULL (típicamente para punteros), pero contra el carácter nulo, que termina las cadenas C. (Alternativamente, ambos son iguales a cero, por lo que pszChar && *pszChar también es una buena condición, si te gusta ese tipo de cosas).

    – Matt Enright

    03/04/2013 a las 13:11

Un enfoque optimizado:

for (char character = *string; character != '\0'; character = *++string)
{
    putchar(character); // Do something with character.
}

La mayoría de las cadenas C tienen terminación nula, lo que significa que tan pronto como el carácter se convierte en '\0' el bucle debe detenerse. los *++string mueve el puntero un byte, luego lo desreferencia y el bucle se repite.

La razón por la que esto es más eficiente que strlen() es porque strlen ya recorre la cadena para encontrar la longitud, por lo que efectivamente estaría recorriendo dos veces (una vez más de lo necesario) con strlen().

sizeof(source) devuelve el número de bytes requerido por el puntero char*. Deberías reemplazarlo con strlen(source) que será la longitud de la cadena que está tratando de mostrar.

Además, probablemente deberías reemplazar printf("%s",source[i]) con printf("%c",source[i]) ya que estás mostrando un personaje.

avatar de usuario
KenE

  1. sizeof() incluye el carácter nulo de terminación. Debería usar strlen() (pero coloque la llamada fuera del ciclo y guárdela en una variable), pero probablemente eso no sea lo que está causando la excepción.
  2. debe usar “%c”, no “%s” en printf; está imprimiendo un carácter, no una cadena.

Esto debería funcionar

 #include <stdio.h>
 #include <string.h>

 int main(int argc, char *argv[]){

    char *source = "This is an example.";
    int length = (int)strlen(source); //sizeof(source)=sizeof(char *) = 4 on a 32 bit implementation
    for (int i = 0; i < length; i++) 
    {

       printf("%c", source[i]);

    }


 }

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad