Cadena C a mayúsculas en C y C++

4 minutos de lectura

Mientras estaba armando una función en mayúsculas en C++, noté que no recibí el resultado esperado en C.

Función C++

#include <iostream>
#include <cctype>
#include <cstdio>

void strupp(char* beg)
{
    while (*beg++ = std::toupper(*beg));
}

int main(int charc, char* argv[])
{
    char a[] = "foobar";
    strupp(a);
    printf("%s\n", a);
    return 0;
}

Salida como se esperaba:

FOOBAR

función C

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

void strupp(char* beg)
{
    while (*beg++ = toupper(*beg));
}

int main(int charc, char* argv[])
{
    char a[] = "foobar";
    strupp(a);
    printf("%s\n", a);
    return 0;
}

La salida es el resultado esperado con el primer carácter que falta

OOBAR

¿Alguien sabe por qué el resultado se trunca al compilar en C?

  • Y si realmente quisieras hacer esto en C++: std::transform(a, a + strlen(a), a, std::toupper);

    – Paul McKenzie

    12/10/2015 a las 16:40

  • ¿Puede explicar por qué esperaba que esto convirtiera una cadena a mayúsculas? Específicamente, ¿por qué esperabas que el lado derecho de la = para ser evaluado antes de la izquierda?

    –David Schwartz

    12/10/2015 a las 16:41

  • Estoy agradecido con todas las personas que dieron su opinión y por la valiosa información proporcionada.

    – Alex Koukoulas

    12/10/2015 a las 16:46

  • @Schullz Creo firmemente que aprender de tus errores es la forma más eficiente de no volver a cometer el mismo error. Por lo tanto, como este problema surgió únicamente de la experimentación y no en un entorno de proyecto de equipo, no creo que haya sido un error escribir este fragmento de código para empezar.

    – Alex Koukoulas

    12/10/2015 a las 23:04

  • @MillieSmith En este caso, ¿importa el orden de qué elemento se hará en mayúsculas? De todos modos, la mayoría, si no todos, los enfoques clásicos de C ++ para mutar una cadena usan std::transform.

    – Paul McKenzie

    13 de octubre de 2015 a las 10:09

avatar de usuario
NathanOliver

El problema es que no hay un punto de secuencia en

while (*beg++ = toupper(*beg));

Así que tenemos un comportamiento indefinido. Lo que el compilador está haciendo en este caso es evaluar beg++ antes de toupper(*beg) En C donde en C++ lo está haciendo al revés.

  • ¿Significa esto que el clásico c-string copia una sola línea? while(*s++ = *t++) ; tiene un comportamiento indefinido?

    – marca h

    13 de octubre de 2015 a las 1:20


  • @markh No, ya que son dos variables diferentes. Esto es sinónimo de while (*s++ = *s++)

    – NathanOliver

    13 de octubre de 2015 a las 1:40

  • @SteveJessop En realidad, while(*s++ = *t++); tiene un comportamiento definido incluso si s == t. La razón strcpy no está definido con regiones superpuestas es que strcpy no se implementa necesariamente con while(*s++ = *t++);.

    – usuario253751

    13 de octubre de 2015 a las 3:11


  • @immibis: punto justo, de acuerdo, está definido. Sin embargo, incluso si strcpy se implementa con ese ciclo, todavía tiene un comportamiento indefinido para una “dirección” de superposición. Si el destino es mayor que el origen y se superponen, entonces el nul de terminación se sobrescribe antes de que se lea y, finalmente, ¡el búfer se desborda! La razón por la que la superposición está prohibida en ambas “direcciones” es por posibles otras implementaciones.

    –Steve Jessop

    13 de octubre de 2015 a las 3:16


avatar de usuario
R Sahú

while (*beg++ = std::toupper(*beg));

conduce a un comportamiento indefinido.

Ya sea *beg++ se secuencia antes o después std::toupper(*beg) no está especificado.

La solución simple es usar:

while (*beg = std::toupper(*beg))
   ++beg;

La línea

while (*beg++ = toupper(*beg));

contiene un efecto secundario en una entidad que se usa dos veces. No puede saber si beg++ se ejecuta o no antes o después de *beg (dentro del toupper). Tiene suerte de que ambas implementaciones muestren ambos comportamientos, ya que estoy bastante seguro de que es lo mismo para C++. (Sin embargo, hubo algunos cambios en las reglas para c ++ 11, de los cuales no estoy seguro; aún así, es un mal estilo).

Simplemente mueva el beg ++ fuera de la condición:

while (*beg = toupper(*beg)) beg++;

avatar de usuario
vishal

con respecto a la respuesta anterior, la ‘f’ nunca se pasa dentro de la función, debe intentar usar esto:

     while ((*beg = (char) toupper(*beg))) beg++;

¿Ha sido útil esta solución?