- Aprender
- Informática
- Programación
- Programación en C
- Arrays y cadenas en C
Arrays y cadenas en C
PrincipianteUnidad 3 de 8 del curso Curso de Programación en C
Lo que aprenderás
- Declara arrays de tamaño fijo, accede a cada elemento mediante su índice, recórrelos con bucles sin pasar del final y compártelos con funciones.
- Declarar e inicializar un array y acceder a sus elementos mediante índicesCrea arrays con un número fijo de elementos, dales valores iniciales y lee o modifica elementos individuales mediante su índice.
- Recorrer arrays con bucles sin salir de sus límitesVisita cada elemento con un bucle de conteo y usa ese patrón para sumar, encontrar el valor máximo, buscar, contar e invertir.
- Pasar arrays a funcionesEscribe funciones que reciban arrays como parámetros, pasa la longitud junto con ellos y determina cuándo puede la función modificar los datos de la función llamadora.
- Declarar e inicializar un array y acceder a sus elementos mediante índices
- Trata los caracteres como códigos enteros pequeños, almacena texto en arrays de
charque terminan con un carácter nulo, procésalo carácter a carácter y observa cómo se almacena el texto UTF-8 en bytes.- Tratar los caracteres como códigos numéricosUsa el tipo
chary las constantes de carácter como números, convierte dígitos y letras mediante operaciones aritméticas y clasifica caracteres con<ctype.h>. - Almacenar texto en cadenas terminadas en nuloExplica cómo se distribuye una cadena de C en un array de
char, por qué necesita un carácter nulo como terminador y en qué se diferencian los literales de cadena de los arrays. - Procesar cadenas carácter a carácterRecorre una cadena hasta su terminador para contar, convertir, invertir, filtrar y cifrar texto, y termina cada cadena nueva con
'\0'. - Explicar cómo se almacena el texto UTF-8 en arrays de charRelaciona los caracteres, los puntos de código Unicode y los bytes UTF-8, y predice qué hacen las funciones de C basadas en bytes con texto que va más allá de ASCII.
- Tratar los caracteres como códigos numéricos
- Mide, copia, concatena, compara y busca cadenas con
<string.h>, y asegúrate de que cada destino tenga espacio para el resultado y su terminador.- Medir, copiar y concatenar cadenasUsa
strlen,strcpyystrcatcorrectamente y calcula cuánto espacio necesita cada destino. - Comparar cadenas y realizar búsquedas en ellasCompara cadenas con
strcmpystrncmp, encuentra caracteres y subcadenas, y divide texto en tokens. - Copiar sin exceder los límites y trabajar directamente con bytes de memoriaUsa correctamente las funciones con límite
strncpy,strncatysnprintf, detecta el truncamiento y copia, rellena y compara arrays completos con las funciones de memoria.
- Medir, copiar y concatenar cadenas
- Almacena tablas y listas de cadenas en arrays de dos o más dimensiones, recórrelos con bucles anidados y pásalos a funciones.
- Declarar y recorrer arrays bidimensionalesDeclara e inicializa tablas de valores, explica cómo se distribuyen sus filas en memoria y procesa filas y columnas con bucles anidados.
- Pasar tablas a funciones y almacenar listas de cadenasEscribe funciones que reciban arrays bidimensionales y guarda varias cadenas en un array de
charde 2 dimensiones o en un array de punteros a cadenas.
- Declarar y recorrer arrays bidimensionales
- Lee las palabras escritas después del nombre de un programa mediante
argcyargv, comprueba cuántas hay y conviértelas de forma segura en números y opciones.- Leer argc y argvDeclara
maincon sus dos parámetros, describe qué contiene cada elemento deargvy comprueba el número de argumentos antes de usar cualquiera de ellos. - Convertir y validar argumentos numéricosConvierte cadenas de argumentos en números con comprobación de errores, rechaza las entradas no válidas y comprueba el rango de los valores antes de usarlos.
- Leer argc y argv
- Reconoce cómo los programas en C leen y escriben fuera de sus arrays, por qué es peligroso y cómo leer y copiar texto para que siempre quepa.
- Reconocer los accesos fuera de los límites y sus efectosExplica por qué C no detiene los accesos fuera de los límites, qué puede ocurrir cuando se producen y qué errores los causan.
- Leer y copiar texto sin exceder los límites del búferLee la entrada con límites de tamaño, detecta las líneas demasiado largas y copia texto solo cuando quepa en su destino.
- Reconocer los accesos fuera de los límites y sus efectos
Guía de estudio de Arrays y cadenas en C
1Almacenar y procesar colecciones de valores con arrays
Los arrays permiten que un mismo bucle trabaje con muchos valores relacionados. El array fija cuánto almacenamiento existe, mientras que los índices seleccionan elementos individuales y una cantidad registra cuántos se utilizan. Aprende cómo las declaraciones establecen valores iniciales, cómo los bucles calculan resultados sin superar un límite y cómo las funciones comparten los elementos de la función llamadora. Ejemplos pequeños relacionan el código con las posiciones exactas que lee o escribe.
1.1 Declarar e inicializar un array y acceder a sus elementos mediante índices
Un array da un nombre a un número fijo de valores del mismo tipo. Sus elementos se encuentran uno junto a otro en memoria. Usa un array cuando se aplique la misma operación a muchos valores, por ejemplo al actualizar un conjunto de puntuaciones.
Crear los elementos
int scores[5] = {90, 72, 85, 64, 99};
int primes[] = {2, 3, 5, 7};
int counts[6] = {0};
La primera declaración crea cinco enteros. El compilador cuenta cuatro valores en el segundo inicializador, por lo que primes tiene cuatro elementos. En el tercero, el primer elemento es explícitamente cero y cada valor de inicialización que falta también pasa a ser cero. Del mismo modo, int a[5] = {1, 2}; contiene 1, 2, 0, 0, 0. Un inicializador designado, disponible desde C99, elige una posición: int b[5] = {[2] = 7}; coloca 7 en el tercer elemento y cero en los demás.
Una declaración local automática como int data[5]; reserva espacio sin proporcionar valores iniciales. Escribe cada elemento antes de leerlo. Los arrays declarados fuera de todas las funciones y los declarados static se inicializan a cero cuando no se proporciona un inicializador explícito.
Acceder a un valor mediante su índice
Los índices empiezan en cero. Para cinco elementos las posiciones válidas van de 0 a 4. scores[1] representa la segunda puntuación; no representa la primera. Un elemento puede usarse dondequiera que se pueda usar una variable normal de su tipo:
scores[1] = 75;
scores[1] += 5;
int last = scores[4];
La segunda puntuación es ahora 80. La última sigue siendo 99. Un índice puede ser una variable o una expresión, por lo que scores[n - 1] accede al último elemento cuando n es el número de elementos y es positivo. En scores[5] no hay ningún elemento al que acceder.
Contar elementos y bytes
sizeof scores mide el array completo en bytes. En un sistema con enteros de 4 bytes, los cinco elementos ocupan 20 bytes. Dividir por el tamaño de un elemento elimina la dependencia del tamaño del entero:
size_t n = sizeof scores / sizeof scores[0];
printf("%zu\n", n);
Esto imprime 5. size_t es el tipo entero sin signo usado para tamaños; %zu lo imprime. Este cálculo funciona donde scores nombra el array real. Un parámetro de función no lleva consigo el tamaño completo del array.
Mantener separados el tamaño y los valores
Un nombre como #define NUM_SCORES 5 permite que la declaración y sus bucles compartan un tamaño. En C17, una declaración local const int n = 5; int a[n]; crea, en cambio, un array de longitud variable: const no convierte n en una expresión constante entera. Su tamaño se elige al ejecutarse la declaración y luego permanece fijo durante el tiempo de vida del array. No puede usar una lista de inicialización. La compatibilidad con arrays de longitud variable es opcional en C11 y C17; C23 añade constexpr para constantes en tiempo de compilación.
Los arrays no se pueden asignar como un todo: b = a; no es válido. Copia sus elementos con un bucle o una función de memoria adecuada. Para dos arrays separados, a == b compara direcciones, no valores de elementos. Compara los elementos correspondientes para comprobar la igualdad de valores. En cambio, una comparación de bytes con memcmp comprueba sus representaciones almacenadas; valores de coma flotante iguales, como el cero positivo y el negativo, pueden tener representaciones diferentes.
Puntos clave
- Los índices de un array van de 0 a una unidad menos que el número de elementos.
- Los valores de inicialización que faltan pasan a ser cero; los elementos locales sin inicializar deben escribirse antes de usarlos.
- Usa
sizeof a / sizeof a[0]solo dondeasea realmente un array. - Un array conserva su tamaño durante todo su tiempo de vida.
- Copia y compara los valores de los arrays elemento por elemento.
1.2 Recorrer arrays con bucles sin salir de sus límites
Un bucle de conteo relaciona las posiciones de un array con una operación. Decide qué elementos contienen datos útiles y visita exactamente esas posiciones. El mismo patrón permite calcular totales, buscar y actualizar valores.
Visitar los elementos utilizados
int t[5] = {12, 15, 9, 14, 10};
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += t[i];
}
double average = sum / 5.0;
El bucle usa los índices 0, 1, 2, 3 y 4. El total pasa por 12, 27, 36, 50 y 60, por lo que el promedio es 12,0. Escribir i <= 5 añade un acceso no válido en el índice 5. Esa pasada adicional es un error de una unidad.
Para calcular un promedio, usa división de coma flotante. Con un total de 61, 61 / 5 da el entero 12; 61 / 5.0 da 12,2. Almacenar después el primer resultado en un double no puede recuperar la fracción ya descartada.
Encontrar un máximo o una coincidencia
Para un array no vacío, inicializa el máximo con su primer valor:
int max = t[0];
for (int i = 1; i < 5; i++) {
if (t[i] > max) max = t[i];
}
La primera comparación reemplaza 12 por 15. Los valores restantes son menores, por lo que permanece 15. Empezar desde cero fallaría para una lista como {-8, -3, -11}: cero es mayor que todos los valores almacenados, pero no está en la lista.
Una búsqueda lineal comprueba los valores en orden:
int found = -1;
for (int i = 0; i < 5; i++) {
if (t[i] == 14) {
found = i;
break;
}
}
Aquí found pasa a ser 3. El valor -1 indica que no hay coincidencia porque no puede ser un índice válido. Indica que no se encontró el valor solo después de comprobar todos los candidatos. Devolver -1 después del primer elemento diferente hace que se pasen por alto coincidencias posteriores en el array.
Contar y reorganizar
Un array de frecuencias almacena un contador por categoría. Para los dígitos, int counts[10] = {0}; proporciona contadores de 0 a 9. Después de verificar d >= 0 && d < 10, counts[d]++ incrementa el contador del dígito d. La comprobación protege el array cuando el valor del dígito procede de la entrada.
Para invertir un array, intercambia pares desde sus extremos:
for (int i = 0; i < 5 / 2; i++) {
int temp = t[i];
t[i] = t[5 - 1 - i];
t[5 - 1 - i] = temp;
}
El primer intercambio cambia 12 por 10. El segundo cambia 15 por 14. El 9 central permanece en su lugar, y queda {10, 14, 9, 15, 12}. Detente a mitad de camino: continuar por las cinco posiciones intercambiaría cada par dos veces.
Llevar la cuenta por separado de la capacidad
Un array con espacio para 100 valores puede contener actualmente solo 37 entradas útiles. Su capacidad es 100; su número de elementos utilizados es 37. Procesa las posiciones inferiores a count. Para añadir un valor, comprueba primero count < CAPACITY, almacénalo en a[count] y luego incrementa count. Recorrer hasta la capacidad puede hacer que se lean posiciones que nunca han recibido valores útiles, aunque esas posiciones estén físicamente dentro del array.
Puntos clave
- Usa un límite de bucle con
<estricto. - Usa división de coma flotante cuando un promedio pueda tener una fracción.
- Inicializa el máximo de un array no vacío a partir de un elemento, incluso cuando todos los datos sean negativos.
- Se determina que una búsqueda ha fallado después de comprobar todos los candidatos.
- Valida un valor antes de usarlo como índice.
- Invierte el array intercambiando solo la primera mitad de los pares.
- El número de elementos utilizados indica cuántos se usan; la capacidad es el espacio disponible.
1.3 Pasar arrays a funciones
Una función puede procesar un array sin recibir una copia separada de cada elemento. La llamada comparte el acceso al almacenamiento de la función llamadora. Pasa el número de elementos junto con el array para que la función sepa dónde detenerse.
Proporcionar los datos y su longitud
#include <stddef.h>
double average(const int a[], size_t n) {
if (n == 0) return 0.0;
int sum = 0;
for (size_t i = 0; i < n; i++) {
sum += a[i];
}
return (double) sum / n;
}
La función llamadora puede declarar int values[] = {7, 8, 10}; y llamar a average(values, sizeof values / sizeof values[0]). Las tres sumas producen 25; convertir sum a double antes de la división produce aproximadamente 8,33. Devolver 0,0 cuando no hay valores es el comportamiento que esta función ha elegido para una entrada vacía. Los valores pequeños de este ejemplo mantienen la suma entera dentro de rango.
En una declaración de parámetro, int a[] se ajusta a int *a. Recibe la dirección del primer elemento. Incluso int a[10] no comprueba ni exige diez elementos. La función llamadora debe proporcionar una longitud que corresponda a los datos disponibles.
Por qué sizeof pierde la longitud
En el punto de llamada, sizeof values mide el array. Dentro de la función, sizeof a mide el parámetro de tipo puntero. Donde los punteros ocupan 8 bytes y los enteros ocupan 4, dividir estos tamaños da 2, independientemente del número de elementos de la función llamadora. Ese resultado no describe ni una copia de dos elementos ni el array original. Mantén la longitud como parámetro explícito.
size_t, declarado por cabeceras como <stddef.h>, es el tipo sin signo que produce sizeof. Puede representar tamaños de objetos, y %zu lo imprime. Usarlo para el índice del bucle evita comparar un índice con signo con una longitud sin signo.
Decidir si los elementos pueden cambiar
El const de const int a[] impide asignar valores a los elementos mediante este parámetro. Es adecuado para una función que calcula un resultado a partir de los datos. Una función destinada a actualizar elementos lo omite:
void zero(int a[], size_t n) {
for (size_t i = 0; i < n; i++) {
a[i] = 0;
}
}
Después de zero(values, 3), los tres elementos de la función llamadora contienen cero. El array sigue teniendo tres elementos. Un parámetro escalar como n es una copia separada; modificar esa copia no cambiaría una variable de cantidad de la función llamadora.
Para producir varios resultados, deja que la función llamadora proporcione un array de salida y su longitud. Una función puede llenar out[i] con cada resultado. Las funciones de C no pueden devolver un array por valor, y devolver la dirección de un array local falla porque ese array deja de existir cuando la función retorna.
Contar hacia atrás con un índice sin signo
Un índice sin signo no puede volverse negativo. En for (size_t i = n - 1; i >= 0; i--), la condición siempre es verdadera; después de cero, el valor pasa por reducción modular a un número positivo grande. Con n == 0, incluso la resta inicial sufre reducción modular. Empieza desde el número de elementos:
for (size_t i = n; i > 0; i--) {
printf("%d\n", a[i - 1]);
}
Con tres elementos, los índices a los que se accede son 2, 1 y 0. Con cero elementos, el cuerpo nunca se ejecuta. Incluye <stdio.h> para printf.
Puntos clave
- Pasa la longitud de un array por separado; no se puede recuperar el número de elementos a partir de un parámetro.
- Las escrituras mediante un parámetro de tipo array modifican los elementos de la función llamadora.
- Usa
constpara un parámetro que solo lee elementos. - La función llamadora proporciona almacenamiento para varios valores de salida.
- Cuenta hacia atrás desde
ny accede ai - 1cuando usessize_t.
2Representar texto con caracteres y cadenas terminadas en nulo
El texto comienza con códigos de caracteres y termina con una regla de almacenamiento: una cadena de C se detiene en su primer byte cero. Aprende en qué se diferencian los caracteres, los literales y los arrays modificables, y luego usa bucles para contar y transformar texto. UTF-8 añade una distinción esencial entre un byte y un punto de código completo. Seguir tanto el texto como su almacenamiento explica por qué una palabra visible puede necesitar más posiciones en un array de lo que sugieren sus letras.
2.1 Tratar los caracteres como códigos numéricos
Un carácter de C se almacena como un código numérico. Esto permite que un programa imprima un símbolo, lo compare con otro o realice operaciones aritméticas con su código. El conjunto de caracteres determina qué número representa cada símbolo.
Leer el código y el carácter
Un char ocupa un byte: sizeof(char) es 1 por definición. Una constante de carácter como 'A' tiene tipo int. En el conjunto de caracteres basado en ASCII que se usa aquí, su código es 65:
printf("%c %d\n", 'A', 'A');
La salida es «A 65». %c muestra el carácter; %d muestra su número. ASCII asigna los códigos de 0 a 127. Los dígitos van de 48 a 57, las letras mayúsculas de 65 a 90, las minúsculas de 97 a 122 y el espacio tiene el código 32.
Las comillas simples y las dobles crean cosas diferentes. 'A' es un código de carácter. "A" es un array que contiene 'A' y un byte cero como terminador. Almacena un carácter con char c = 'A'; y compáralo con c == 'A'.
Escribir caracteres que necesitan secuencias de escape
| Escritura en C | Carácter |
|---|---|
'\n' | Salto de línea, código ASCII 10 |
'\t' | Tabulador, código ASCII 9 |
'\\' | Barra invertida |
'\'' | Comilla simple |
'\0' | Carácter nulo, código 0 |
El carácter nulo es distinto del dígito visible '0', cuyo código ASCII es 48. Una cadena usa el carácter nulo para marcar su final.
Convertir códigos en valores útiles
El estándar de C garantiza códigos de dígitos consecutivos. Después de comprobar que c es un dígito, c - '0' produce su valor. Por tanto, '7' - '0' es 7, no 55. Restar el código inicial elimina la posición del dígito dentro del conjunto de caracteres.
Las letras ASCII también son consecutivas, por lo que restar 'A' convierte una letra mayúscula en una posición de 0 a 25. Un desplazamiento de César de tres posiciones usa:
char shifted = (c - 'A' + 3) % 26 + 'A';
Para 'X', restar 65 da 23; sumar tres da 26; el resto de dividir entre 26 es cero; sumar 65 devuelve 'A'. La expresión 'X' + 3 por sí sola da el código 91, que es '['. Las operaciones aritméticas con letras dependen de un orden de letras como el de ASCII; C garantiza dígitos consecutivos, pero no exige letras consecutivas.
Clasificar y convertir con ctype.h
Incluye <ctype.h> para usar isdigit, isalpha, isalnum, isspace, isupper, islower, toupper y tolower. Las comprobaciones devuelven un valor distinto de cero si hay coincidencia y cero en caso contrario. toupper('q') devuelve 'Q'; toupper('3') deja el dígito sin cambios. isspace reconoce separadores como el espacio, el tabulador y el salto de línea.
Un char sin especificador puede tener signo. Un byte mayor que 127 puede convertirse entonces en un valor negativo, que no es un argumento válido para estas funciones salvo que sea el marcador especial de entrada EOF. Al procesar bytes de una cadena, conviértelos primero:
if (isalpha((unsigned char) c)) {
c = (char) toupper((unsigned char) c);
}
En la configuración regional «C» predeterminada, estas funciones reconocen las letras básicas, no los caracteres UTF-8 completos de varios bytes. La conversión explícita hace que el byte sea un argumento válido; no decodifica UTF-8.
Puntos clave
- Las constantes de carácter usan comillas simples; los literales de cadena usan comillas dobles.
\0es un carácter de valor cero, no el dígito0.- Resta
'0'a un carácter que representa un dígito para obtener su valor. - Las operaciones con posiciones de letras usan aquí el orden ASCII.
- Convierte un byte de una cadena a
unsigned charantes de una llamada a ctype. - Una comprobación de ctype devuelve un valor distinto de cero si hay coincidencia, no necesariamente 1.
2.2 Almacenar texto en cadenas terminadas en nulo
Una cadena de C es una secuencia de caracteres que termina con '\0'. El terminador forma parte del almacenamiento, pero no de la longitud del texto. C no tiene un tipo de cadena integrado independiente: los caracteres ocupan un array.
Ver los bytes en el array
char word[] = "cat";
char name[20] = "Ada";
word contiene cuatro bytes: 'c', 'a', 't', '\0'. El tamaño de su array es 4 y strlen(word) es 3. Incluye <string.h> para usar strlen. El array name, más grande, contiene las tres letras, su terminador y dieciséis bytes cero más. Su capacidad es 20, mientras que su longitud actual es 3.
Un inicializador carácter a carácter puede crear la misma cadena:
char word[] = {'c', 'a', 't', '\0'};
Omitir el último elemento crea tres caracteres sin terminador de cadena. C también permite char word[3] = "cat";, que llena las tres posiciones y omite el byte cero. Un array así no es una cadena de C. Una función como strlen o printf con %s sigue leyendo hasta encontrar un byte cero, por lo que no puede usar de forma segura ese array de tres bytes como texto.
Elegir un array modificable o un literal
| Declaración | Dónde está el texto | ¿Pueden cambiar sus caracteres? |
|---|---|---|
char a[] = "hello"; | Una copia en el array a | Sí |
const char *p = "hello"; | Un literal de cadena al que apunta p | No |
a[0] = 'H'; cambia la copia a «Hello». Un literal no debe modificarse. Aunque se asigne a un char * sin calificador, escribir mediante ese puntero produce comportamiento indefinido. Escribir const char * hace visible esa restricción para el compilador.
El compilador concatena los literales de cadena contiguos: "Hello, " "world" produce el mismo texto que "Hello, world". La cadena resultante sigue teniendo un solo terminador final. Esto es útil para dividir un literal largo entre varias líneas del código fuente.
Imprimir y modificar el texto
printf("%s\n", word);
printf("%c\n", word[0]);
La primera llamada imprime la cadena completa. La segunda imprime su primer carácter. Un literal de cadena en printf va entre comillas dobles porque es texto que contiene un formato; %c recibe un código de carácter.
Una asignación a un elemento modifica un carácter almacenado. Con char name[20] = "Ada";, establecer name[0] = 'E'; produce «Eda». Establecer después name[1] = '\0'; produce «E» como cadena. Los bytes de 'a' y del terminador anterior siguen existiendo más adelante en el array, pero las operaciones con cadenas se detienen en el primer cero.
Un array no puede recibir texto de reemplazo mediante name = "Bob"; después de la declaración. Copia los caracteres en él mediante una llamada comprobada a strcpy o un bucle, e incluye el terminador. La longitud del texto de reemplazo debe ser menor que la capacidad.
Representar la ausencia de texto
La cadena vacía "" sigue ocupando un byte para '\0'. Tiene longitud cero y se puede comprobar con name[0] == '\0'. Una cadena vacía es una cadena real con un terminador; un puntero nulo, en cambio, no apunta a ningún almacenamiento de cadena.
Puntos clave
- Una cadena de C termina en su primer
'\0'. - La capacidad incluye el terminador; la longitud de la cadena lo excluye.
- Un array de caracteres sin terminador no puede pasarse como cadena de C.
- Las copias de literales en arrays son modificables; los propios literales no lo son.
- Escribir un terminador antes acorta el texto sin cambiar el tamaño de su array.
2.3 Procesar cadenas carácter a carácter
El terminador de una cadena da a un bucle su punto de parada. Visita los bytes anteriores para contar, convertir o filtrar texto. Al crear una cadena nueva, el propio programa debe escribir un nuevo terminador.
Recorrer hasta el final una vez
for (size_t i = 0; s[i] != '\0'; i++) {
/* Process s[i]. */
}
En cada pasada, la condición pregunta si el byte actual pertenece al texto. El bucle se detiene antes del terminador. Llamar a strlen(s) en esa condición puede volver a recorrer toda la cadena en cada pasada. Comprueba directamente el byte actual o calcula size_t len = strlen(s); una sola vez cuando la longitud vaya a permanecer sin cambios.
Para convertir a mayúsculas, usa un array modificable y <ctype.h>:
for (size_t i = 0; s[i] != '\0'; i++) {
s[i] = (char) toupper((unsigned char) s[i]);
}
«Hello, World 42» se convierte en «HELLO, WORLD 42». La conversión conserva la coma, los espacios y los dígitos. La conversión a un tipo sin signo hace que cada byte almacenado sea un argumento válido para ctype.
Contar categorías e inicios de palabras
El texto original «Hello, World 42» tiene 15 bytes de texto: 10 letras, dos dígitos, dos espacios y una coma. Los contadores separados pueden usar isalpha, isdigit e isspace. Decide qué es una palabra antes de contarla. Para una secuencia de letras, una palabra nueva empieza cuando una letra sigue a un carácter que no es una letra o es el primer carácter:
int in_word = 0;
size_t words = 0;
for (size_t i = 0; s[i] != '\0'; i++) {
int letter = isalpha((unsigned char) s[i]) != 0;
if (letter && !in_word) words++;
in_word = letter;
}
El ejemplo tiene dos secuencias de letras, «Hello» y «World». Los dígitos no forman una palabra según esta definición. Actualizar in_word en cada pasada permite que la puntuación termine una secuencia.
Invertir solo el texto
Para una cadena de un solo byte por carácter, obtén len una vez y luego intercambia s[i] con s[len - 1 - i] mientras i < len / 2. Invertir «stressed» intercambia su primera y última letras, luego el siguiente par, hasta que se convierte en «desserts». El byte cero permanece en el índice len. Empezar un intercambio en s[len] llevaría ese cero al principio. Invertir bytes de esta manera es adecuado para texto ASCII; los caracteres de varios bytes necesitan decodificarse antes de reorganizarlos.
Construir un resultado filtrado
Usa índices diferentes para leer y escribir, porque se omiten algunos bytes de entrada:
char in[] = "a1b2c3";
char out[sizeof in];
size_t j = 0;
for (size_t i = 0; in[i] != '\0'; i++) {
if (isalpha((unsigned char) in[i])) {
out[j++] = in[i];
}
}
out[j] = '\0';
El resultado es «abc». El destino tiene espacio suficiente porque el filtrado no puede alargar esta entrada. Sin out[j] = '\0';, la salida no tiene un final de cadena definido.
Para un cifrado César, desplaza las letras mayúsculas con respecto a 'A' y las minúsculas con respecto a 'a', y luego copia los demás bytes sin cambios. Con la clave 13, «Hello, World!» se convierte en «Uryyb, Jbeyq!». Repetir ese desplazamiento restablece el original porque dos desplazamientos suman 26. Una comparación como s[i] == 'a' comprueba un carácter; usa strcmp para comparar texto completo.
Puntos clave
- Comprueba el byte actual o guarda la longitud para evitar recorridos completos repetidos.
- Mantén índices de lectura y escritura separados al filtrar.
- Escribe un terminador después de construir una cadena nueva.
- Invierte los bytes del texto sin mover el terminador.
- Define un límite de palabra antes de escribir un contador de palabras.
- Aplica los desplazamientos de letras ASCII por separado a mayúsculas y minúsculas.
2.4 Explicar cómo se almacena el texto UTF-8 en arrays de char
La longitud del texto puede referirse a un número de bytes o a un número de puntos de código Unicode. Estas cantidades suelen diferir. Un array de char de C expone bytes individuales, por lo que sus índices y las funciones de cadenas no siguen automáticamente caracteres completos que no sean ASCII.
Distinguir caracteres, puntos de código y bytes
Una codificación de caracteres describe cómo se almacena el texto. ASCII usa los códigos de 0 a 127 para letras básicas, dígitos, signos de puntuación y caracteres de control. Unicode asigna puntos de código a caracteres de muchos sistemas de escritura: «é» tiene el punto de código U+00E9 y «€» tiene U+20AC. UTF-8 codifica valores escalares de Unicode usando de uno a cuatro bytes.
Los puntos de código ASCII conservan sus codificaciones de un byte. La «é» precompuesta usa dos bytes, 0xC3 y 0xA9; «€» usa tres. Muchos puntos de código individuales de emojis usan cuatro bytes. Un símbolo mostrado puede contener varios puntos de código, por lo que incluso un recuento de puntos de código no siempre coincide con el número de símbolos visibles.
Medir una cadena UTF-8
char s[] = "café";
printf("%zu %zu\n", strlen(s), sizeof s);
Con texto de ejecución en UTF-8, esto imprime «5 6». Las tres primeras letras usan tres bytes y «é» usa dos, lo que suma cinco bytes de texto. El terminador añade el sexto byte de almacenamiento. s[3] es el primer byte de «é», no la letra completa.
Un corte después de cuatro bytes conservaría 0xC3, pero eliminaría su byte de continuación 0xA9. El resultado ya no sería UTF-8 válido. Por tanto, un límite de búfer expresado en bytes requiere comprobar los límites entre caracteres si el programa trunca texto UTF-8.
Contar los bytes iniciales en UTF-8 válido
Un byte de continuación empieza con los bits 10. Su valor va de 0x80 a 0xBF. Un byte inicial o un byte ASCII no tiene ese patrón:
size_t points = 0;
for (size_t i = 0; s[i] != '\0'; i++) {
unsigned char c = (unsigned char) s[i];
if ((c & 0xC0) != 0x80) points++;
}
La máscara 0xC0 conserva solo los dos bits más significativos; 0x80 representa el patrón 10 en esas posiciones. La comprobación cuenta «café» como cuatro puntos de código al contar sus cuatro bytes iniciales. Supone que el UTF-8 es válido y no valida secuencias mal formadas ni combina puntos de código en símbolos visibles.
Elegir operaciones que conservan la codificación
Copiar una cadena UTF-8 completa conserva sus bytes. Concatenar cadenas completas, comparar sus secuencias de bytes para comprobar su igualdad y buscar un carácter ASCII o una subcadena UTF-8 completa también funcionan. Los bytes de continuación UTF-8 no pueden confundirse con caracteres ASCII ni con bytes iniciales.
strcmp ordena valores de bytes sin signo, por lo que su orden difiere del orden alfabético específico de cada idioma. En UTF-8, las letras latinas acentuadas normales tienen bytes iniciales mayores que el de 'z' en ASCII. Por tanto, una comparación de bytes coloca esas letras después de 'z', independientemente de las convenciones del diccionario.
En la configuración regional «C» predeterminada, toupper e isalpha procesan un byte y no decodifican «é» como una letra. La conversión explícita a unsigned char hace válida la llamada, pero no puede convertirla en una conversión Unicode entre mayúsculas y minúsculas. Para esa tarea se necesitan funciones de caracteres anchos o una biblioteca Unicode. Un bucle de César limitado a ASCII puede conservar las letras acentuadas si solo modifica los bytes de A–Z o a–z.
El byte cero es la codificación UTF-8 de U+0000; los demás puntos de código codificados no contienen ningún byte cero. Esto se ajusta a la convención de terminación de C. UTF-16 puede incluir bytes cero dentro de texto ordinario codificado, por lo que un array de bytes UTF-16 no puede procesarse como una cadena normal de char.
Puntos clave
strlencuenta bytes, también en texto UTF-8.- Un punto de código Unicode puede ocupar varios bytes.
- Un índice de char puede apuntar al interior de un carácter codificado.
- Contar los bytes que no son de continuación solo cuenta puntos de código en UTF-8 válido.
- La igualdad byte a byte funciona para texto codificado idéntico; el orden de los bytes no es el orden del diccionario.
- Las llamadas a ctype de un solo byte no decodifican UTF-8.
3Utilizar las funciones estándar de cadenas
La biblioteca estándar proporciona operaciones habituales con texto, pero cada función espera un tipo de entrada concreto y un significado concreto para su argumento de tamaño. Aprende a medir, copiar, añadir, comparar y buscar cadenas, y luego elige el formato con límite o las operaciones con bytes cuando corresponda. Comprobar la capacidad e interpretar los valores de retorno convierte una llamada breve a una función en una operación predecible sobre un almacenamiento conocido.
3.1 Medir, copiar y concatenar cadenas
Las funciones de <string.h> trabajan con texto terminado en nulo. Pueden determinar su longitud, copiarlo o añadir más texto, pero las funciones de copia no averiguan la capacidad del destino. Calcula el almacenamiento necesario antes de escribir.
Medir la longitud sin el terminador
strlen(s) devuelve un size_t que indica el número de bytes anteriores al primer byte cero. Así, strlen("hello") es 5 y strlen("") es cero. Imprime el resultado con %zu.
char buf[64] = "hi";
printf("%zu %zu\n", strlen(buf), sizeof buf);
Esto imprime «2 64». El primer resultado mide el texto actual; el segundo mide el almacenamiento disponible en el array. Una copia posterior puede cambiar el primero sin cambiar el segundo. Ambas llamadas son útiles aquí porque buf es realmente un array y ya contiene una cadena válida.
Copiar una cadena completa
strcpy(dest, src) copia el texto y su byte cero final. La capacidad necesaria es la longitud del origen más uno:
char dest[12];
const char *src = "Maple";
if (strlen(src) < sizeof dest) {
strcpy(dest, src);
}
«Maple» usa cinco bytes de texto y un terminador, por lo que cabe. La comparación estricta < es importante: un origen cuya longitud sea igual a la capacidad no deja espacio para su byte cero. Si la comprobación falla, el programa debe gestionar el error antes de usar el destino como una nueva cadena.
Una asignación a un array como dest = src; no puede reemplazar su contenido. Asignar una variable char * a otra es válido, pero solo copia una referencia al mismo almacenamiento. No crea otra copia de los caracteres.
Añadir texto a una cadena existente
strcat(dest, src) encuentra primero el terminador que ya está en dest. Reemplaza ese terminador por el primer byte del origen y escribe un nuevo terminador después del texto añadido. La capacidad del destino debe cubrir las dos longitudes actuales más uno.
char full[16];
strcpy(full, "Ada");
strcat(full, " ");
strcat(full, "Lovelace");
Las longitudes aumentan de 3 a 4 y a 12. El resultado final «Ada Lovelace» necesita 13 bytes de almacenamiento y deja tres bytes sin usar. Un destino de 12 bytes sería un byte demasiado pequeño, aunque coincida con la longitud del texto visible.
Nunca añadas texto a un búfer local sin inicializar. char out[20]; strcat(out, "hi"); no proporciona a strcat un final de texto definido que pueda encontrar. Empieza con char out[20] = "";, escribe out[0] = '\0'; o haz que la primera operación sea una copia comprobada.
Tener en cuenta el almacenamiento y el coste de los recorridos
El origen y el destino no deben solaparse en strcpy ni en strcat. Mover texto dentro del mismo búfer puede crear un solapamiento aunque ambas ubicaciones sean válidas por separado. memmove es la función destinada a regiones de bytes solapadas.
strlen debe recorrer la cadena hasta el terminador. strcat debe recorrer el destino actual antes de añadir texto. Por tanto, las adiciones repetidas en un bucle vuelven a recorrer texto que ya se ha construido. Al construir muchas partes, conserva la longitud actual de la salida y escribe cada parte en ese índice, comprobando la capacidad restante y manteniendo el terminador. Una longitud conocida solo es útil mientras siga coincidiendo con el contenido real.
Puntos clave
strlenmide el texto actual;sizeofaplicado a un array mide su capacidad.- Una copia necesita la longitud del origen más un byte.
- Una concatenación necesita las longitudes de ambas cadenas más un byte.
- Inicializa el destino como una cadena antes de añadir texto.
- Copiar o añadir cadenas con regiones de memoria solapadas no es válido.
3.2 Comparar cadenas y realizar búsquedas en ellas
La comparación de cadenas responde preguntas sobre el texto, mientras que la búsqueda de cadenas encuentra una posición dentro de ese texto. Ninguna de las dos tareas se realiza comparando nombres de arrays con ==. Usa el resultado de la biblioteca según lo que represente: el signo de una comparación, una longitud o la ubicación de una coincidencia.
Comparar texto y prefijos
strcmp(a, b) compara los bytes correspondientes como valores unsigned char hasta encontrar una diferencia o el final de una cadena. Su resultado es cero para textos iguales, negativo cuando a va primero y positivo cuando va después. Solo se especifica el signo; no esperes exactamente -1 o 1.
if (strcmp(command, "quit") == 0) {
puts("Goodbye");
}
La comparación explícita con cero significa igualdad. Una condición if (strcmp(command, "quit")) sin comparación entra cuando los textos son distintos, porque un valor distinto de cero es verdadero. Comparar command == "quit" compararía ubicaciones de almacenamiento.
En el orden ASCII, «apple» va antes que «banana» por la primera letra. «Zebra» va antes que «apple» porque la mayúscula 'Z' tiene el código 90 y la minúscula 'a' tiene el código 97. «app» va antes que «apple» porque se encuentra su byte cero antes que la 'l' de la otra cadena. Este es un orden de bytes, no una comparación de diccionario.
strncmp(a, b, n) compara como máximo n bytes. strncmp(s, "--", 2) == 0 reconoce un prefijo de dos guiones, pero no significa que toda la cadena sea solo «--». El C estándar no tiene una función para comparar cadenas completas sin distinguir mayúsculas de minúsculas. Un programa puede comparar por sí mismo los bytes convertidos; POSIX proporciona strcasecmp en <strings.h>.
Buscar una ubicación
Usa strchr para la primera aparición de un carácter, strrchr para la última y strstr para la primera subcadena completa. Devuelven un puntero a la ubicación de la coincidencia o NULL si no hay ninguna.
char name[] = "report.final.txt";
char *extension = strrchr(name, '.');
if (extension != NULL) {
printf("%s\n", extension);
}
Esto imprime «.txt», incluido el punto encontrado. Empezar desde el primer punto con strchr imprimiría «.final.txt». strstr(name, "final") encuentra la parte final que empieza por «final.txt»; buscar «draft» devuelve NULL. Comprueba si el resultado es NULL antes de imprimirlo o leerlo.
Localizar un separador o dividir texto
strcspn(s, set) cuenta los bytes iniciales que no corresponden a ninguno de los caracteres de set. Con "oak:pine,birch" y el conjunto ":,", se detiene en los dos puntos. Para una cadena de entrada válida, este patrón elimina el primer salto de línea:
buf[strcspn(buf, "\n")] = '\0';
Si no hay salto de línea, el índice devuelto es la longitud de la cadena, por lo que la asignación vuelve a escribir el terminador que ya está allí.
strtok divide una cadena modificable usando cualquier carácter de un conjunto de delimitadores:
char colors[] = "red, green,blue";
char *token = strtok(colors, " ,");
while (token != NULL) {
puts(token);
token = strtok(NULL, " ,");
}
Los tokens son «red», «green» y «blue». La primera llamada proporciona el array; las llamadas posteriores pasan NULL para continuar. La función escribe bytes cero en la entrada y mantiene un estado oculto entre llamadas. Usa almacenamiento modificable y no esperes que la cadena original con sus separadores permanezca intacta. Los delimitadores consecutivos no producen tokens vacíos.
Puntos clave
- Usa
strcmp(a, b) == 0para comprobar que los textos son iguales. - Interpreta el resultado de una comparación por su signo, no por su magnitud exacta.
- Una coincidencia de prefijo no establece la igualdad de las cadenas completas.
- Los resultados de búsqueda requieren comprobar si el puntero es nulo.
strcspndevuelve la longitud de un prefijo;strtokmodifica su entrada y recuerda su posición.- La ordenación de cadenas sigue los códigos de los bytes sin signo.
3.3 Copiar sin exceder los límites y trabajar directamente con bytes de memoria
Un límite de longitud solo es útil cuando describe la cantidad correcta. Algunas funciones limitan los bytes de origen, otras la capacidad del destino, y las funciones de memoria manejan bytes directamente sin finales de cadena. Lee las condiciones de cada función antes de elegir su límite.
Saber qué significa n
strncpy(dest, src, n) escribe exactamente n posiciones cuando el origen es más corto, rellenando con bytes cero. Cuando el origen tiene al menos n bytes de texto, copia esos bytes sin terminador. Para un array de capacidad positiva, una copia truncada y terminada en nulo es:
strncpy(dest, src, sizeof dest - 1);
dest[sizeof dest - 1] = '\0';
La asignación final es esencial cuando el origen llena el límite. Truncar un nombre o comando aún puede cambiar su significado, así que rechaza las entradas demasiado largas cuando se necesite una copia completa.
strncat(dest, src, n) añade como máximo n bytes de texto y luego un terminador. No recibe la capacidad total. Para una cadena válida que ya está dentro de un array de destino, el espacio restante para texto es sizeof dest - strlen(dest) - 1. Pasar sizeof dest como n puede desbordarlo.
Dar formato y detectar el truncamiento
snprintf, declarada en <stdio.h>, recibe la capacidad total del destino. Si la capacidad es mayor que cero, escribe como máximo un byte de texto menos y después un terminador:
char buf[8];
int needed = snprintf(buf, sizeof buf, "%s-%d", "item", 2026);
if (needed < 0) {
puts("Formatting error");
} else if ((size_t) needed >= sizeof buf) {
puts("Text did not fit");
}
El resultado completo «item-2026» tiene nueve bytes de texto. El búfer almacena «item-20» y su byte cero, mientras que needed es 9. El valor de retorno cuenta el texto que se habría producido, sin incluir el terminador. Comprueba si el resultado es negativo antes de convertirlo a size_t.
Copiar y rellenar bytes
memcpy(dest, src, n) copia exactamente n bytes, incluidos los bytes cero, sin buscar un terminador. Para dos arrays de enteros del mismo tamaño, memcpy(b, a, sizeof a) copia todo su almacenamiento cuando las regiones no se solapan. Donde cada uno de cinco enteros ocupa cuatro bytes, esa cantidad es 20 bytes. memmove copia bytes con un comportamiento definido para regiones solapadas.
memset(a, 0, sizeof a) rellena cada byte con cero y pone a cero un array de enteros. Su segundo argumento describe cada byte, no cada elemento. Con enteros de cuatro bytes, rellenar con 1 produce los bytes 01 01 01 01, lo que da 16 843 009 en la representación habitual, no el entero 1. Usa un bucle para asignar valores enteros distintos de cero.
memcmp(a, b, n) compara los bytes almacenados. Cero significa que esas secuencias de bytes coinciden. Para comprobar la igualdad de valores, compara los elementos: los valores de coma flotante 0.0 y -0.0 se consideran iguales al compararlos, aunque sus representaciones pueden diferir.
Reconocer otras familias de bibliotecas
strlcpy y strlcat de BSD se incorporaron a POSIX en 2024, pero no son funciones principales de C17. Devuelven la longitud que intentaron crear; un resultado al menos tan grande como el tamaño proporcionado indica truncamiento. strlcpy termina la cadena cuando el tamaño es positivo. strlcat solo la termina si el texto existente acaba dentro de ese tamaño. Están disponibles en glibc 2.38 y posteriores. Las funciones opcionales del anexo K, como strcpy_s, no están presentes en muchas bibliotecas, incluida glibc.
Puntos clave
strncpypuede omitir el terminador;strncatnecesita espacio para uno nuevo.snprintfdevuelve la longitud completa del texto necesario o un valor negativo si hay un error.- Un resultado de formato no negativo al menos tan grande como la capacidad indica truncamiento.
- Las funciones de memoria cuentan bytes y no se detienen en cero.
- Usa
memmovepara regiones solapadas. memsetrellena bytes;memcmpcompara representaciones.
4Organizar datos en arrays multidimensionales
Las tablas organizan valores mediante más de una posición. Una tabla de C almacena filas de igual ancho en secuencia, y los bucles anidados permiten que un programa trabaje por filas o por columnas. Aprende a declarar esa estructura, pasarla a una función y mantener ambos índices dentro de los límites. Las listas de texto presentan una elección de diseño útil: las filas de caracteres modificables reservan un espacio fijo, mientras que los arrays de punteros apuntan a cadenas almacenadas en otro lugar.
4.1 Declarar y recorrer arrays bidimensionales
Una tabla necesita un índice de fila y un índice de columna. En C, un array bidimensional es un array cuyos elementos son a su vez arrays. Cada fila tiene el mismo número de elementos y cada índice tiene su propio límite.
Declarar filas y columnas
int grid[3][4];
int m[2][3] = {{1, 2, 3}, {4, 5, 6}};
grid contiene tres filas con cuatro enteros cada una: doce enteros en total. Sus índices de fila van de 0 a 2; sus índices de columna van de 0 a 3. grid[1][2] accede al tercer valor de la segunda fila.
Las llaves de inicialización anidadas muestran la agrupación por filas. Los elementos cuyo valor de inicialización falta pasan a ser cero. Puedes dejar que el compilador cuente las filas en int m[][3] = {{1, 2, 3}, {4, 5, 6}};, pero debes proporcionar el número de columnas. Sin él, el compilador no podría determinar dónde termina cada fila.
Seguir el almacenamiento por filas
C almacena una fila completa antes de empezar la siguiente. En grid, los primeros cuatro enteros almacenados son la fila 0, los cuatro siguientes son la fila 1 y los últimos cuatro son la fila 2. grid[1][2] es el séptimo entero desde el inicio, en la posición de elemento 6 si se cuenta desde cero: una fila completa de cuatro y luego dos elementos más.
Donde los enteros ocupan cuatro bytes, una fila usa dieciséis bytes y toda la tabla usa cuarenta y ocho. En el lugar de la declaración:
size_t rows = sizeof grid / sizeof grid[0];
size_t cols = sizeof grid[0] / sizeof grid[0][0];
La primera división da 3 y la segunda da 4. Una fila es un array por derecho propio, por eso sizeof grid[0] mide más de un entero.
Recorrer y sumar la tabla
int sales[2][3] = {{4, 0, 7}, {5, 2, 1}};
int total = 0;
for (int r = 0; r < 2; r++) {
int row_sum = 0;
for (int c = 0; c < 3; c++) {
row_sum += sales[r][c];
}
printf("%d\n", row_sum);
total += row_sum;
}
La primera fila produce 11 y la segunda 8. Sumar esos totales por fila da 19. Restablecer row_sum dentro del bucle exterior inicia un total nuevo para cada fila. Si se inicializara una sola vez antes de ambos bucles, el segundo valor impreso también incluiría la primera fila.
Para los totales por columna, coloca el bucle de columnas fuera y el de filas dentro, accediendo igualmente a sales[r][c]. Los tres totales pasan a ser 9, 2 y 8, que suman de nuevo 19. Cambiar el orden del recorrido no exige cambiar el significado de los dos índices. Recorrer primero por filas sigue el almacenamiento contiguo y suele mejorar el uso de la caché en tablas grandes.
Mantener cada dimensión dentro de sus límites
grid[c][r] intercambia el significado de los índices. Si c llega a 3, solicita una cuarta fila que no existe. El hecho de que el objeto completo contenga doce enteros no permite superar el límite de una fila con un índice de columna.
Escribe dos operaciones de indexación separadas: grid[1][2]. En C17, grid[1, 2] evalúa la expresión con coma y selecciona grid[2], una fila, en lugar de un elemento. Más dimensiones aplican la misma idea repetidamente: int cube[2][3][4] tiene 24 elementos enteros, seleccionados mediante tres índices.
Puntos clave
- Un array bidimensional es un array de filas de igual ancho.
- Las filas se almacenan una detrás de otra en orden por filas.
- Mantén separados los límites de filas y columnas.
- Restablece un acumulador de fila o columna al iniciar un grupo nuevo.
- Solo se puede deducir la primera dimensión de un inicializador.
4.2 Pasar tablas a funciones y almacenar listas de cadenas
Una función que recibe una tabla necesita información suficiente para identificar cada fila. Una lista de cadenas añade otra elección: almacenar los caracteres en filas de igual ancho o almacenar referencias a cadenas de distintas longitudes.
Indicar el ancho de fila en un parámetro de tabla
void double_grid(int rows, int g[][4]) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < 4; c++) {
g[r][c] *= 2;
}
}
}
La primera dimensión puede omitirse porque el número de filas se pasa por separado. El ancho 4 define el tipo de cada fila. Sin él, g[r][c] no tendría una separación conocida entre filas. Una declaración con int g[][] no es válida. Los cambios realizados mediante este parámetro permanecen en la tabla de la función llamadora; un parámetro de tabla de solo lectura puede usar const int g[][4].
Desde C99, los compiladores que admiten parámetros de tipo modificado variablemente aceptan dimensiones declaradas anteriormente en la lista de parámetros:
void print_grid(int rows, int cols, int g[rows][cols]);
GCC y Clang admiten esta forma de C17. Permite que una función reciba distintos anchos de fila; pasa dimensiones positivas que coincidan con la tabla real. C23 exige compatibilidad con estos tipos de parámetros, mientras que los objetos automáticos de tipo array de longitud variable siguen siendo una característica opcional independiente. Los parámetros de ancho fijo son útiles cuando la compatibilidad del compilador es limitada.
Almacenar cadenas en filas
char days[7][10] = {
"Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"
};
Cada fila tiene almacenamiento para diez caracteres, independientemente de la longitud de su texto actual. «Wednesday» necesita las diez posiciones: nueve letras y un terminador. days[2] selecciona toda esa fila como una cadena; days[2][0] selecciona 'W'.
Una fila se puede imprimir con %s, medir con strlen o comparar con strcmp. También puede recibir una copia comprobada. strcpy(days[0], "Mon"); cabe en diez bytes y modifica el texto de la fila 0. La fila sigue teniendo diez bytes de ancho y la siguiente permanece en la misma ubicación. Un texto de reemplazo de diez bytes necesitaría once bytes y no cabría.
Almacenar referencias a literales
const char *names[] = {"Ann", "Bartholomew", "Li"};
Esto declara un array de punteros. Cada elemento apunta a un literal con su propia longitud más un terminador. names[1] apunta a «Bartholomew» y names[1][0] es 'B'. Los literales no deben modificarse.
Los elementos de tipo puntero pueden cambiar aunque los caracteres de los literales no puedan hacerlo. names[0] = "Anna"; cambia el literal al que apunta el primer elemento; no amplía «Ann» en el mismo espacio de almacenamiento. En la forma de filas de 2 dimensiones, un elemento es un array de caracteres de ancho fijo y no puede reasignarse de esa manera. Elige filas modificables para texto que se edita en el mismo espacio de almacenamiento y referencias a literales para una lista de opciones de texto fijo. El parámetro de la línea de comandos argv tiene forma de array de punteros, aunque los caracteres de los argumentos proporcionados son modificables.
Puntos clave
- Los parámetros de tabla necesitan todas las dimensiones posteriores a la primera.
- Una dimensión pasada por separado debe coincidir con la tabla real.
- Cada fila de cadena necesita su propio terminador dentro de su ancho fijo.
- Un array de punteros almacena referencias, no filas de caracteres de igual ancho.
5Procesar argumentos de la línea de comandos
Una línea de comandos proporciona texto a un programa al iniciarse. El número de argumentos, la agrupación del intérprete de comandos y las operaciones con cadenas permiten que el programa interprete ese texto sin suponer que existe un argumento o que ya contiene un número. Sigue un proceso con comprobaciones desde argv hasta un valor utilizable: verifica su presencia, conviértelo por completo, detecta errores de conversión y aplica el rango que el programa acepta realmente.
5.1 Leer argc y argv
Los argumentos de la línea de comandos permiten que quien llama a un programa le proporcione texto al iniciarlo. El entorno de ejecución pone esas cadenas a disposición de main. Comprueba cuántas llegaron antes de acceder a ellas mediante índices.
Leer la lista de argumentos
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
printf("%d: %s\n", i, argv[i]);
}
return 0;
}
Incluye <stdio.h> para la salida. argc es el número de argumentos y argv es la lista de cadenas. La forma equivalente del parámetro char **argv describe la misma interfaz. El bucle empieza en 1 porque el índice 0 normalmente contiene el nombre con el que se inició el programa.
En un intérprete de comandos habitual, ejecutar ./greet Ada Lovelace proporciona tres cadenas: «./greet», «Ada» y «Lovelace». Así, argc es 3 y el último argumento del usuario es argv[2]. Hay un puntero nulo en argv[argc], aquí argv[3]; es un valor centinela después de las cadenas de argumentos reales.
Dejar que el intérprete agrupe el texto
Las comillas afectan a cómo el intérprete construye los argumentos. Ejecutar ./greet "Ada Lovelace" proporciona un argumento del usuario que contiene un espacio. Sus comillas agrupan las palabras y no pasan a formar parte del texto del argumento. argc es ahora 2.
Los intérpretes de tipo Unix también pueden expandir patrones antes de que comience el programa. En ./count *.txt, el programa suele recibir como argumentos separados los nombres que coinciden con el patrón según el intérprete. Recibe las cadenas resultantes, no una petición para expandir el patrón por sí mismo. El comportamiento exacto de la expansión depende del intérprete y de su configuración.
Rechazar la falta o el exceso de argumentos
Si un programa necesita exactamente un argumento del usuario, exige argc == 2 antes de usarlo:
if (argc != 2) {
printf("Usage: %s name\n", argv[0]);
return 1;
}
printf("Hello, %s\n", argv[1]);
Cuando argc es 1, argv[1] es el puntero nulo centinela y no puede pasarse a strlen ni imprimirse con %s. Los índices posteriores al centinela están fuera del array de argumentos.
Devolver cero desde main indica éxito. Un estado distinto de cero, como el 1 anterior, indica al intérprete que el programa no terminó correctamente. <stdlib.h> también proporciona EXIT_SUCCESS y EXIT_FAILURE.
Tratar cada argumento como una cadena
argv[i][0] accede al primer carácter del argumento; strlen(argv[i]) mide sus bytes de texto; strcmp(argv[i], "-v") == 0 comprueba una opción completa. Un argumento que parece numérico sigue siendo texto y debe convertirse antes de realizar operaciones aritméticas.
argv[0] suele registrar cómo se inició el programa, pero puede estar vacío cuando esa información no está disponible. Es útil para mensajes, no como comprobación de identidad fija. Los caracteres de los argumentos pueden modificarse durante la ejecución del programa, pero el almacenamiento proporcionado no permite suponer que quepa un reemplazo más largo. Para añadir una extensión o alargar el texto de otro modo, cópialo primero en un búfer de tamaño adecuado.
Puntos clave
argccuenta las cadenas de argumentos proporcionadas, incluida la entrada habitual con el nombre de inicio.- Comprueba el número de argumentos antes de leer un argumento del usuario.
argv[argc]es un puntero nulo, no una cadena de argumento vacía.- Las comillas del intérprete pueden mantener espacios dentro de un argumento.
- Usa operaciones de cadenas para el texto de los argumentos y conversión para los números.
5.2 Convertir y validar argumentos numéricos
Un argumento numérico llega como caracteres, no como un entero. Una conversión fiable comprueba tres cuestiones distintas: si algún dígito formó un número, si la conversión usó el texto requerido y si el valor resultante está permitido.
Evitar perder la información de error
atoi, declarada en <stdlib.h>, realiza una conversión sencilla. Convierte «13» en 13, pero también convierte «12abc» en 12. Devuelve cero tanto para «0» como para texto que no empieza por un número, como «abc». Un resultado fuera de rango produce comportamiento indefinido, por lo que una comprobación de solo dígitos seguida de atoi sigue siendo insegura para entradas muy largas.
Una regla de formato como «solo uno o más dígitos» necesita un recorrido separado. Rechaza una cadena vacía y exige que cada byte cumpla isdigit((unsigned char) c). Esa regla acepta «13» y rechaza «13a», «-5» y «». Comprueba la forma del texto, no si el valor cabe en un entero de la máquina.
Usar strtol y examinar dónde se detuvo
#include <errno.h>
#include <stdlib.h>
char *end;
errno = 0;
long count = strtol(argv[1], &end, 10);
if (end == argv[1] || *end != '\0' || errno == ERANGE) {
puts("Enter a whole number");
return 1;
}
if (count < 1 || count > 100) {
puts("Count must be from 1 to 100");
return 1;
}
Este fragmento va después de una comprobación del número de argumentos y usa <stdio.h> para puts. El 10 selecciona la conversión decimal. end recibe la ubicación donde se detuvo la conversión; &end permite que la función almacene esa ubicación. *end lee el carácter que hay allí. No se necesita aritmética de punteros.
Para «13a», el valor devuelto es 13, pero *end es 'a', por lo que se rechaza el texto. Para una cadena vacía o «abc», end es igual al inicio del argumento, lo que muestra que no se procesó ningún número. Ambas comprobaciones son necesarias: comprobar solo el cero final aceptaría por error una cadena vacía.
Antes de cada conversión, restablece errno a cero. Un valor fuera del rango de long hace que strtol devuelva un extremo del rango y establezca ERANGE. Sin el restablecimiento, un error anterior podría parecer asociado a esta conversión. Comprueba antes de convertir el resultado a int; usa INT_MIN e INT_MAX de <limits.h> cuando se acepte todo el rango de int.
Aplicar la regla propia del programa
strtol acepta caracteres en blanco iniciales y un signo opcional. Decide si se permiten esas formas. Si la interfaz exige solo dígitos, realiza el recorrido para comprobar que no esté vacía y que solo contenga dígitos, además de las comprobaciones de conversión. Después de una conversión correcta, comprueba el rango permitido por la aplicación antes de usar un valor como cantidad o índice. «0» puede ser texto numérico perfectamente válido y aun así no ser válido para una cantidad que deba ser positiva.
Un programa de César que acepte una clave no negativa comprueba primero argc, luego su formato de solo dígitos y después el resultado completo de strtol y el rango. Reducir una clave válida con % 26 produce un desplazamiento de 0 a 25 antes de las operaciones con letras. La clave 27 tiene el efecto de la clave 1. Comprueba el rango antes de una conversión explícita a un tipo de menor rango o de cualquier operación que pueda desbordarse. Para valores decimales, strtod proporciona la interfaz correspondiente para la posición final y el error de rango.
Puntos clave
- Los argumentos que parecen numéricos aún necesitan conversión.
atoino puede distinguir un cero válido de un fallo de conversión.- Comprueba que
strtolhaya leído algo y procesado todo el texto requerido. - Restablece
errno, compruebaERANGEy luego comprueba el rango permitido por la aplicación. - Un recorrido para comprobar que solo hay dígitos no descarta el desbordamiento.
- Valida un valor antes de convertirlo a un tipo de menor rango o usarlo como índice.
6Prevenir accesos fuera de los límites y desbordamientos de búfer
Los errores de límites relacionan varias ideas anteriores: un bucle puede dar una pasada de más, el texto puede necesitar un byte adicional y una función puede perder la referencia de la capacidad de un array. Aprende a identificar el acceso no válido antes de predecir sus efectos. Luego lee y copia la entrada dentro de límites conocidos, comprobando por separado el éxito y que esté completa para que un búfer con capacidad suficiente contenga los datos que el programa pretendía aceptar.
6.1 Reconocer los accesos fuera de los límites y sus efectos
Todo acceso a un array necesita un índice válido. C no exige una comprobación de límites en tiempo de ejecución, por lo que el programador debe mantener el índice dentro del objeto. Un acceso fuera de su rango tiene comportamiento indefinido: el lenguaje no garantiza ningún resultado.
Reconocer un acceso no válido
Para int a[5], los índices válidos van de 0 a 4. El índice 5 ya es demasiado grande y -1 es negativo. Un compilador puede diagnosticar un error visible, pero muchos índices no válidos dependen de la entrada en tiempo de ejecución y no se rechazan durante la compilación.
Un programa defectuoso puede parecer que funciona, cerrarse inesperadamente o producir valores imprevistos. Una escritura puede corromper el estado cercano; el síntoma puede aparecer después en un cálculo sin relación. Una lectura puede acceder a bytes fuera del objeto previsto. Ninguna de las dos operaciones tiene un resultado fiable. Repetir una ejecución correcta no puede establecer que el acceso sea válido.
Contar cada escritura, incluido el terminador
char name[8];
strcpy(name, "Christopher");
«Christopher» tiene once bytes de texto. Copiarlo también escribe el terminador, por lo que esta llamada intenta escribir doce bytes en ocho posiciones. Eso es un desbordamiento de búfer. En sistemas reales, un desbordamiento puede dañar otros datos o información de control. Históricamente, ataques como el gusano Morris de 1988 aprovecharon esos defectos en el manejo de entradas.
Un desbordamiento puede ser de un solo byte:
char s[5];
for (int i = 0; i <= 5; i++) {
s[i] = 'x';
}
El cuerpo se ejecuta seis veces y escribe en el índice 5. Cambiar la condición a i < 5 mantiene cinco escrituras de caracteres dentro del array, pero sigue sin crear una cadena. Para una cadena de cuatro caracteres 'x', escribe solo en los índices de 0 a 3 y luego almacena '\0' en el índice 4.
Validar índices calculados
Una tabla de frecuencias puede convertir un carácter en un índice, pero la resta por sí sola no garantiza el rango:
int counts[26] = {0};
if (c >= 'a' && c <= 'z') {
counts[c - 'a']++;
}
Con el orden ASCII, esa comprobación limita el resultado de 0 a 25. Para 'A' o un byte de puntuación, usar c - 'a' sin la comprobación podría crear un índice negativo. Comprueba el valor original antes de acceder mediante el índice; comprobarlo después de escribir es demasiado tarde.
Para una tabla, valida la fila y la columna por separado. En int g[2][3], un índice de columna de 3 no es válido aunque la siguiente fila esté contigua en memoria. El almacenamiento de la tabla completa no permite superar el límite de una fila.
Usar comprobaciones adecuadas para cada operación
Un bucle sobre un array usa un límite superior estricto; añadir un elemento exige comprobar el número de elementos utilizados frente a la capacidad; copiar una cadena exige comprobar la longitud del texto más uno. Las funciones reciben las longitudes o capacidades reales de sus funciones llamadoras. Estas comprobaciones se refieren a cantidades diferentes, por lo que un solo tamaño fijo no puede sustituirlas a todas.
Compila con advertencias como -Wall -Wextra. La opción -fsanitize=address -g de GCC y Clang puede informar de muchos accesos no válidos en las rutas ejecutadas y mostrar la ubicación en el código fuente. Estas pruebas ayudan a encontrar errores, pero las rutas no ejecutadas siguen requiriendo razonar sobre los límites. Revisa cada lectura y escritura mediante un índice identificando su objeto, su límite y la condición que mantiene válido ese índice.
Puntos clave
- Las lecturas y escrituras fuera de los límites tienen comportamiento indefinido.
- Una ejecución correcta no demuestra que un índice sea válido.
- Una cadena copiada incluye su terminador en el número de bytes escritos.
- Valida los datos antes de obtener de ellos un índice de array.
- Comprueba cada dimensión de una tabla por separado.
- Las advertencias y los sanitizadores ayudan a detectar defectos en las rutas probadas.
6.2 Leer y copiar texto sin exceder los límites del búfer
La longitud de la entrada la controla quien la proporciona. Indica a las funciones de lectura un límite real del búfer y comprueba lo que devuelven. Luego decide si los datos forman una línea completa y si cumplen las reglas propias del programa.
Leer una palabra con un ancho de campo
Para char word[16];, scanf("%15s", word) lee como máximo quince caracteres que no sean caracteres en blanco y añade '\0'. El ancho deja una de las dieciséis posiciones para el terminador. %s sin ancho no tiene límite de longitud; gets tenía el mismo problema fundamental para las líneas y se eliminó de C en C11.
Comprueba que scanf devuelva 1 antes de usar una palabra. Lee una palabra, no una línea completa con espacios. Los bytes sobrantes de la palabra pueden quedar sin leer, por lo que un ancho protege el almacenamiento sin determinar si toda la entrada es aceptable.
Leer una línea con fgets
char buf[8];
if (fgets(buf, sizeof buf, stdin) == NULL) {
return 1;
}
Aquí fgets lee como máximo siete caracteres y escribe un byte cero final. Conserva un salto de línea cuando llega a él antes del límite. Una línea que contiene «hello» y un salto de línea se convierte en "hello\n" más el terminador. Una línea final que termina al llegar al fin de archivo sin salto de línea también puede leerse correctamente. Si no se leyó ningún carácter antes del fin de archivo o se produjo un error de lectura, el resultado es NULL; no proceses ese búfer como entrada nueva.
Distinguir un salto de línea almacenado de una línea parcial
Busca un salto de línea antes de eliminarlo:
size_t end = strcspn(buf, "\n");
int had_newline = buf[end] == '\n';
buf[end] = '\0';
Incluye <string.h>. Si no se almacenó ningún salto de línea, end es la longitud del texto y la asignación vuelve a escribir el terminador existente. La ausencia de un salto de línea puede significar una línea parcial, que el búfer se llenó exactamente antes de un salto de línea o que una línea final terminó en el fin de archivo. Por sí sola no demuestra que queden caracteres por leer.
Para la línea de entrada «abcdefghij» y un búfer de ocho bytes, la primera lectura almacena «abcdefg» y la siguiente puede leer «hij\n». Tratar el segundo fragmento como una respuesta separada dividiría una sola entrada lógica. Un programa puede rechazar una línea a la que le falte un salto de línea obligatorio, o leer y descartar el resto antes de volver a preguntar. Define la política de entrada antes de implementarla.
Para nombres de hasta treinta caracteres ASCII más un salto de línea y un terminador, usa 32 bytes. Para UTF-8, ese es un límite de bytes: treinta caracteres visibles pueden necesitar más almacenamiento.
Copiar solo después de comprobar todos los requisitos
char user[10];
if (argc != 2) return 1;
if (strlen(argv[1]) >= sizeof user) {
puts("Name too long");
return 1;
}
strcpy(user, argv[1]);
La comprobación del número de argumentos va primero. Después, la comprobación de longitud admite como máximo nueve bytes de texto y deja la décima posición para el cero. Una función que escribe debería recibir la capacidad explícitamente, como en read_name(out, capacity), porque sizeof out dentro de ella mide un parámetro de tipo puntero.
Para una entrada numérica, lee una línea completa y conviértela con strtol, comprobando la posición final, el error de rango y el rango de valores permitido. Una llamada fallida a scanf("%d", &n) puede dejar sin leer el texto problemático; repetirla sin comprobar puede fallar indefinidamente con los mismos bytes. Como mínimo, comprueba su número de asignaciones realizadas y gestiona la entrada no válida antes de reintentar.
Puntos clave
- Establece el ancho de lectura de una palabra en una unidad menos que la capacidad del búfer.
- Comprueba el resultado de una lectura antes de usar su búfer.
fgetssolo conserva un salto de línea cuando llega a él dentro del límite.- La ausencia de un salto de línea no demuestra por sí sola que quede entrada por leer.
- Reserva espacio para los bytes de texto, el salto de línea cuando se conserve y el terminador.
- Comprueba que el argumento exista antes de medir y copiar su texto.
- Pasa la capacidad del búfer a una función que escriba en él.
Ejemplos de Arrays y cadenas en C
1Seguir un array desde su declaración hasta la llamada a una función
13 pasos
- 1IntroducciónDar un nombre a varios valores
Un array contiene un número fijo de elementos de un mismo tipo. Un bucle selecciona posiciones, mientras que una función puede trabajar con el mismo almacenamiento mediante un parámetro de tipo array.
Sigue cuatro lecturas de un sensor desde su declaración hasta un total y un promedio. En cada paso, distingue tres cantidades: el número de elementos, el último índice válido y el número de bytes usados para el almacenamiento.
- 2EjemploLeer las posiciones iniciales
int readings[4] = {11, 16, 13};Hay cuatro elementos, con índices de 0 a 3. El inicializador proporciona 11, 16 y 13 en las tres primeras posiciones. El valor omitido pasa a ser cero, por lo que el array es
{11, 16, 13, 0}.El cero es una regla de inicialización, no una señal de que el array solo tenga tres elementos. Un array local sin inicializador necesitaría que se escribieran sus valores antes de usarlo.
- 3ExplicaciónContar los elementos en la declaración
size_t n = sizeof readings / sizeof readings[0];El numerador mide los cuatro elementos y el denominador mide uno. Donde
intocupa cuatro bytes, esto es dieciséis dividido entre cuatro, lo que da 4. La misma expresión funciona con otro tamaño de entero.readings[3]es el último elemento.readings[4]está más allá del final aunque el número de elementos del array sea 4.size_tes el tipo sin signo usado para este resultado de tamaño. - 4DesafíoCambiar la última lectura
La declaración sigue siendo
int readings[4] = {11, 16, 13};. ¿Qué asignación reemplaza el cero por 20 y qué número de elementos resulta?---reveal---
Usa
readings[3] = 20;. Los valores resultantes son{11, 16, 13, 20}y el número de elementos sigue siendo 4. Una asignación a un elemento cambia un valor, no el número de posiciones. El índice 4 estaría una posición más allá del límite y no puede añadir almacenamiento a este array. - 5EjemploConstruir el total pasada a pasada
int sum = 0; for (size_t i = 0; i < n; i++) { sum += readings[i]; }Con
{11, 16, 13, 20}, la suma acumulada pasa a ser 11, 27, 40 y 60. Después del índice 3, i pasa a ser 4 y la condición deja de cumplirse antes de otro acceso.Empezar la suma en cero da al primer valor un punto de partida limpio. El límite superior estricto permite que el bucle visite exactamente los cuatro elementos existentes.
- 6Idea claveConservar la parte fraccionaria de un promedio
Para estas cuatro lecturas,
(double) sum / nda 15,0. La conversión explícita ocurre antes de la división, por lo que la operación puede producir un resultado fraccionario cuando cambie el total.Si el total fuera 61, la división entera
sum / 4produciría 15, mientras quesum / 4.0produciría 15,25. Asignar a un double el resultado entero ya truncado solo produciría 15,0; no recuperaría la fracción descartada. - 7ConsejoElegir un candidato inicial válido
La búsqueda de un máximo necesita un valor inicial tomado de un array no vacío. Para
{-6, -2, -9}, inicializamaxen -6 y luego reemplázalo por -2 cuando aparezca ese valor mayor. La última comparación deja -2 sin cambios.Inicializar max en cero devolvería cero, que no está presente. Para una búsqueda lineal, la regla de parada correspondiente también importa: una diferencia no demuestra que la búsqueda haya fallado; aún hay que comprobar los elementos posteriores.
- 8DesafíoMantener la búsqueda en marcha
Una búsqueda de 13 comprueba
{11, 16, 13, 20}. Después de comprobar el índice 0 devuelve -1 porque 11 es distinto de 13. ¿Qué debería cambiar y dónde está la coincidencia?---reveal---
Sigue comprobando después de una diferencia y devuelve -1 solo cuando fallen todos los candidatos. Aquí el índice 1 también es diferente, pero el índice 2 coincide. Una búsqueda exitosa puede detenerse ahí. La primera comparación fallida describe un elemento, no todo el array.
- 9ConexiónTrasladar el promedio a una función
double mean(const int a[], size_t n);El parámetro de tipo array comparte el acceso a los elementos de la función llamadora. No lleva consigo su número, por lo que el segundo parámetro lo proporciona.
constimpide escrituras accidentales mediante a en esta operación de solo lectura.Calcula el número de elementos donde se declara
readingsy llama amean(readings, n). Dentro de mean,sizeof amide un parámetro de tipo puntero en lugar del array de cuatro elementos de la función llamadora. - 10EjemploGestionar el rango vacío antes de dividir
double mean(const int a[], size_t n) { if (n == 0) return 0.0; int sum = 0; for (size_t i = 0; i < n; i++) sum += a[i]; return (double) sum / n; }Para las cuatro lecturas pequeñas, el total sigue siendo 60 y el resultado es 15,0. Para n igual a cero, el resultado elegido es 0,0 y no se produce ningún acceso al array ni división. La función llamadora debe pasar un número de elementos utilizables preciso.
- 11DesafíoExplicar un cambio en el array de la función llamadora
Otra función recibe
int a[], size_t ny establece en cero cadaa[i]visitado. ¿Qué ocurre con las lecturas de la función llamadora y cómo podría una función que solo calcula el total impedir esas escrituras?---reveal---
Los elementos de la función llamadora pasan a ser cero porque la función escribe en el almacenamiento compartido del array. Sus cuatro posiciones siguen existiendo. Una función que solo calcula el total debería usar
const int a[], lo que invalida las asignaciones a elementos mediante a. Cambiar una copia escalar de n no cambiaría una variable de cantidad de la función llamadora. - 12DesafíoUsar solo las lecturas que existen
Un búfer tiene capacidad 10, pero solo se usan cuatro lecturas. Hay que añadir una lectura nueva antes de calcular un promedio. ¿Qué comprobaciones y qué número de elementos debería usar el programa?
---reveal---
Comprueba que el número de elementos utilizados, 4, sea menor que la capacidad 10. Escribe en el índice 4 y luego actualiza el número de elementos a 5. Pasa ese número de elementos utilizados a mean para que procese exactamente los cinco valores. Pasar la capacidad incluiría posiciones que no se han proporcionado como lecturas.
- 13RepasoRelacionar cada cantidad con su función
Una declaración crea las posiciones, un bucle visita las utilizadas y una función recibe explícitamente el número de elementos utilizables. Un parámetro de solo lectura evita que los cálculos sobrescriban la entrada.
Al revisar código con arrays, sigue el primer y el último índice visitados y el estado de cada acumulador. Para bucles hacia atrás con
size_t, empieza en n, continúa mientras i sea positivo y accede aa[i - 1]para que un rango vacío no requiera restar a cero.
2Realizar operaciones de texto con los bytes almacenados
16 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónObservar tanto el texto como el almacenamiento
- 2ExplicaciónLeer un carácter como código
- 3DesafíoVolver al inicio dentro del alfabeto
- 4EjemploConstruir una cadena modificable
- 5Idea claveMover el final sin mover el almacenamiento
- 6DesafíoDejar una posición para el terminador
- 7EjemploSeparar la lectura de la escritura
- 8EjemploTerminar la cadena nueva
- 9DesafíoInvertir letras sin el terminador
- 10ConsejoClasificar bytes con argumentos válidos
- 11EjemploDistribuir una letra acentuada en UTF-8
- 12ExplicaciónReconocer los bytes de continuación
- 13DesafíoMedir una nueva palabra codificada
- 14ConexiónElegir operaciones que mantengan los caracteres completos
- 15DesafíoComprobar un atajo propuesto para el texto
- 16RepasoLocalizar el final y los límites de los caracteres
3Crear, buscar y dar formato al texto de forma segura
14 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónIdentificar las condiciones de cada función
- 2EjemploEmpezar con una copia completa
- 3EjemploAñadir texto en el final existente
- 4DesafíoDecidir si cabe otra concatenación
- 5ExplicaciónUsar cero para reconocer textos iguales
- 6EjemploLeer desde una ubicación encontrada
- 7DesafíoExaminar una comprobación de comando basada en un prefijo
- 8ConsejoTener en cuenta que la división en tokens cambia el texto
- 9EjemploDar formato dentro de una capacidad conocida
- 10DesafíoInterpretar el mismo formato con menos espacio
- 11Idea claveUn límite puede contar bytes de origen
- 12EjemploMover una región solapada
- 13DesafíoConservar un resultado completo después de desplazarlo
- 14RepasoDistinguir los bytes de los resultados de texto
4Leer una tabla y elegir cómo almacenar una lista de cadenas
10 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónDar dos índices a cada posición
- 2EjemploColocar valores en filas
- 3EjemploRestablecer el total de una fila al comenzarla
- 4DesafíoCambiar la agrupación y conservar los índices
- 5ExplicaciónIndicar a una función el ancho de fila
- 6EjemploReservar una cadena terminada en nulo por fila
- 7Idea claveLas referencias permiten cadenas de diferentes longitudes
- 8DesafíoReemplazar texto en el almacenamiento adecuado
- 9DesafíoMantener válidas ambas dimensiones en una función
- 10RepasoMantener visible la forma de la tabla
5Validar una selección de la línea de comandos
11 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónRecibir el texto antes de interpretarlo
- 2EjemploRelacionar un comando del intérprete con sus entradas
- 3ExplicaciónComprobar el número de argumentos antes de convertir
- 4DesafíoAgrupar correctamente un nombre
- 5ConsejoUn entero devuelto no es suficiente
- 6EjemploExaminar una conversión completa
- 7ExplicaciónComprobar el rango propio de la selección
- 8DesafíoDetectar texto que parece parcialmente numérico
- 9Idea claveEl formato y el valor siguen reglas distintas
- 10DesafíoCombinar la agrupación y la validación numérica
- 11RepasoComprobar la presencia, la conversión y el propósito
6Corregir una rutina de entrada con límites
13 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónLimitar la escritura y comprobar el resultado
- 2EjemploEncontrar la escritura adicional
- 3Idea claveLa última posición válida puede contener el terminador
- 4DesafíoComprobar un índice obtenido de un byte
- 5ExplicaciónLeer una palabra dejando espacio para el terminador
- 6EjemploLeer un fragmento de línea con límite
- 7EjemploObservar dónde se divide una línea larga
- 8ConsejoExaminar un salto de línea antes de eliminarlo
- 9DesafíoCalcular el espacio para una línea completa
- 10EjemploComprobar una copia antes de escribir
- 11DesafíoDistinguir un prefijo seguro de una respuesta aceptada
- 12ConexiónUsar diagnósticos y razonar sobre los límites
- 13RepasoMantener separadas cuatro comprobaciones
Ejercicios de Arrays y cadenas en C
Set 1: Valores de arrays, bucles y llamadas a funciones10 Preguntas de Práctica
Pregunta 1 de 10
a[3] después de int a[5] = {6, 9};?Mostrar respuestaOcultar respuesta
Pregunta 2 de 10
int a[7]; donde int ocupa 4 bytes. ¿Qué pareja indica sizeof a y el último índice válido?Mostrar respuestaOcultar respuesta
Pregunta 3 de 10
int a[] = {-12, -4, -9};, ¿qué valor debería devolver una búsqueda del máximo?Mostrar respuestaOcultar respuesta
Pregunta 4 de 10
¿Qué imprime este código?
int a[] = {3, 8, 5, 2};
int sum = 0;
for (int i = 1; i < 4; i++) sum += a[i];
printf("%d", sum);
Mostrar respuestaOcultar respuesta
Pregunta 5 de 10
{2, 9, 7, 4} devuelve -1 al encontrar el primer elemento diferente. ¿Dónde debería devolver el valor de fallo?Mostrar respuestaOcultar respuesta
Pregunta 6 de 10
a[i] con a[5 - 1 - i] para i = 0 e i = 1, partiendo de {4, 7, 1, 8, 6}?Mostrar respuestaOcultar respuesta
Pregunta 7 de 10
void set_first(int a[]) ejecuta a[0] = 11;. ¿Qué valor tiene el primer elemento del array de la función llamadora después de la llamada?Mostrar respuestaOcultar respuesta
Pregunta 8 de 10
void f(int a[], size_t n), los punteros ocupan 8 bytes y los enteros 4 bytes. ¿Cuánto vale sizeof a / sizeof a[0]?Mostrar respuestaOcultar respuesta
Pregunta 9 de 10
size_t para n e i. Debe imprimir un array en orden inverso y funcionar para n = 0. ¿Qué parámetro y bucle cumplen ambos requisitos?Mostrar respuestaOcultar respuesta
Pregunta 10 de 10
a[4] de int a[4]?Mostrar respuestaOcultar respuesta
Set 2: Caracteres, terminadores de cadenas y UTF-810 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
c de tipo char a isalpha sin arriesgarse a usar un byte negativo como argumento?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
'6' - '0'?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
('W' - 'A' + 5) % 26 + 'A'?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
char color[] = "amber";?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
char s[8] = "planet"; s[3] = '\0'; s[0] = 'P';?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
char tag[4] = "east"; printf("%s", tag);?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
"m8n2p" y las escribe en un array de salida suficientemente grande. ¿Qué debe escribir después de la p final?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
char s[] = "lamp"; intercambiando s[i] con s[len - i] mientras i < len / 2, donde len es strlen(s). ¿Cuáles son el valor final de strlen(s) y la capacidad, que no cambia?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
41 C3 B1 42 00. Un programa escribe cero en el índice de byte 2. ¿Cuáles son el nuevo valor de strlen y la validez UTF-8 del texto?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 3: Elegir y comprobar operaciones de biblioteca10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
"silver"?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
char label[10] = "blue"; strcat(label, "berry"); almacenar su resultado completo?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
char out[20]; strcat(out, "go");. ¿Por qué no es una forma válida de empezar a construir una cadena?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
char *p = strrchr("archive.backup.bin", '.');, ¿qué texto comienza en p?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
"on,,off;wait". Se llama a strtok(s, ",;") y luego se repite strtok(NULL, ",;") hasta obtener NULL. ¿Qué tokens se producen y se conserva s?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
char b[6]; int r = snprintf(b, sizeof b, "%s:%d", "job", 84);?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
"AB". El programa ejecuta strncat(b, "123456", sizeof b - strlen(b) - 1). ¿Cuáles son el texto resultante y el número de bytes almacenados, incluido el cero?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
char s[] = "wxyz"; memmove(s, &s[1], 4);, ¿qué contiene s como cadena?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 4: Tablas, listas de texto y entrada al inicio10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
int table[4][6]?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
sizeof table[0] para int table[3][5]?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
{{2, 7, 4}, {6, 1, 5}}. Un bucle inicializa sum una sola vez a cero antes de ambos bucles, suma una fila cada vez e imprime después de cada fila sin restablecer sum. ¿Qué valores se imprimen y cómo se corrige?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
char names[3][width] almacene «Iris», «Magnolia» y «Ash» como cadenas ASCII completas?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
char rows[2][5] = {"oak", "elm"}; y const char *refs[] = {"oak", "elm"};. Debe reemplazar la primera palabra de la lista por el texto completo «cedar». ¿Qué tratamiento es válido para cada forma de almacenamiento?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
./mark "West Room" 9. ¿Cuáles son argc y argv[2]?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 5: Límites de entrada y resultados completos10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
char word[18]?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
"pine\n" en un array de 10 bytes. ¿Cuáles son el valor de strlen del resultado y el índice de su terminador?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
char b[6] sin otras lecturas. ¿Qué texto almacena la segunda llamada?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
counts[c - 'a']++ para una entrada de caracteres sin comprobar?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
char out[6]. A la llamada snprintf(out, sizeof out, "%s%d", "R-", 1234) le sigue if (r > sizeof out) reject();, donde r es su valor de retorno no negativo. ¿Qué se almacena, esa comprobación lo rechaza y qué debe cambiar?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
ERANGE y exige *end == '\0', pero no comprueba end == start. ¿Qué entrada no válida puede seguir aceptándose como cero?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
41 C3 A9 E2 82 AC 00. Un programa la copia en char b[5] y reserva la última posición para el cero. ¿Cuáles son el valor resultante de strlen, el número de bytes iniciales y la validez de la codificación?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 6: Seguir y corregir operaciones combinadas en C10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
int a[4] = {[2] = 9};?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
int g[3][4], ¿cuál es la posición de elemento de g[2][1], contando desde cero, en el almacenamiento por filas?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
./pick "" blue. ¿En qué se diferencian argv[1] y argv[argc]?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
int a[], size_t n y ejecuta a[0] = 0; n = 0;. La función llamadora proporcionó {5, 8, 2} y el número de elementos 3, y luego calcula la suma entera de sus elementos dividida por ese número. ¿Qué promedio y qué número de elementos de la función llamadora resultan?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
strncpy(b, "planet", sizeof b);. El programa requiere la palabra original completa. ¿Qué corrección cumple el requisito?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
int values[4] = {14, 28, 35, 49};. Convierte por completo «04» con strtol en base decimal, acepta selecciones de 1 a 4 y luego lee values[selected]. Debe permitir las cuatro selecciones y asignar la selección 1 al primer valor. ¿Qué ocurre y qué regla de indexación lo corrige?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
¿Te atascas con una pregunta tuya? Ayuda con Tareas
Términos Clave
A
Acceso fuera de los límites
a[8] en un array de ocho elementos no es válido aunque una ejecución de prueba parezca devolver un valor útil.Acumulador
sum en cero permite que cada sum += a[i] añada el siguiente elemento del array al total actual.Ancho de campo
%s limita el número de caracteres de entrada almacenados antes del byte cero terminador adicional.char word[10], la conversión %9s reserva el décimo byte disponible para el terminador.Ancho de fila
int g[][6] acepta filas de seis enteros de ancho, mientras que la función llamadora proporciona el número de filas por separado.argc
argc indica el número de cadenas de argumentos proporcionadas a main, normalmente incluida la cadena usada para iniciar el programa../label red blue en un intérprete normal da a argc el valor 3: el nombre de inicio y dos colores.Argumento de la línea de comandos
argv
argv proporciona acceso a las cadenas de argumentos mediante índices, seguidas de un puntero nulo en la posición indicada por argc.argc, un programa puede usar strcmp(argv[1], "-v") para reconocer su primera opción.Array (arreglo)
int levels[6] reserva seis enteros; actualizar levels[2] cambia el tercer valor almacenado.Array bidimensional
int board[4][6] proporciona 24 enteros, a los que se accede mediante cuatro índices de fila válidos y seis índices de columna válidos.Array de frecuencias
counts[4]++ añade una aparición al recuento de ese dígito.Array de longitud variable
const int n = 6; int a[n]; crea un array de longitud variable porque n no es una expresión constante.Array de punteros a cadenas
const char *names[] = {"Al", "Mina"} almacena dos referencias y permite reemplazar una referencia.Array de salida
out[i] mientras la función llamadora conserva la propiedad del array.ASCII
'8' - '0' produce 8 porque los códigos de los caracteres de dígitos son consecutivos.atoi
atoi convierte una parte numérica inicial a int sin informar de errores de forma fiable y tiene comportamiento indefinido en caso de desbordamiento.atoi, por lo que un número devuelto no demuestra que toda la entrada fuera numérica.B
Bucles anidados
Búfer
Búsqueda lineal (secuencial)
{3, 8, 2} encuentra una coincidencia en el índice 2 después de comprobar los elementos anteriores que no coinciden.Byte de continuación
10 y sigue a un byte inicial dentro de un punto de código codificado en varios bytes.C
Cadena de C
char pet[] = "dog" contiene tres letras seguidas de un carácter de valor cero.Cadena vacía
char message[20] = "" proporciona un destino vacío válido para una concatenación posterior que quepa en su capacidad.Capacidad
Clasificación de caracteres
<ctype.h>.isdigit((unsigned char) c) da un resultado distinto de cero cuando el byte almacenado representa un dígito decimal.Codificación de caracteres
Columna
g[r][c].g[r][c].Comparación según los valores de los bytes
strcmp coloca una letra latina acentuada después de la z ASCII porque su byte inicial tiene un valor mayor.Comportamiento indefinido
Concatenación
Configuración regional (locale)
toupper aplicado byte a byte en la configuración regional «C» no convierte una letra acentuada UTF-8 completa en su forma mayúscula.Constante de carácter
int, que representa un código de carácter, como el código de una letra.printf("%c %d", 'B', 'B') muestra la letra B y el valor numérico 66.Conversión de texto a número
% 26.D
Delimitador
Desbordamiento de búfer
Desplazamiento de César
División en tokens
strtok lo hace modificando la entrada y recordando una posición.strtok(NULL, ",") continúa dividiendo la misma entrada modificable en lugar de empezar de nuevo.E
Elemento
int a[3] = {8, 1, 6}, el elemento a[1] contiene 1 y puede recibir otro entero.ERANGE
ERANGE identifica un error de rango comunicado mediante errno, como un resultado de strtol demasiado grande o pequeño para long.errno en cero antes de la conversión y luego comprueba si es ERANGE antes de aceptar una secuencia larga de dígitos.Error de una unidad (off-by-one)
i <= n hace que un recorrido de n elementos con índices desde cero intente un acceso adicional en el índice n.Estado de salida
main indica que terminó correctamente.F
fgets
fgets lee una entrada de línea con límite, conserva un salto de línea si llega a él y añade un terminador cuando lee texto correctamente.Fila
int table[2][5], table[1] representa la segunda fila, que contiene cinco posiciones de enteros.Filtrado
Fin de archivo
fgets aún puede tener éxito si leyó caracteres antes de llegar a esa condición.fgets reciba ese texto final.Í
Índice
I
Inicializador
int hits[4] = {3} inicializa el primer contador en 3 y los otros tres contadores en cero.L
Límite de palabra
Línea parcial
fgets, por lo que el segundo fragmento no debería convertirse en una respuesta nueva.Lista de cadenas de capacidad fija por fila
char labels[5][12], cada etiqueta tiene doce bytes de almacenamiento aunque su texto actual sea más corto.Literal de cadena
const char *label = "ready" apunta a un literal; una copia modificable puede usar char label[] = "ready".Longitud de una cadena
M
Máscara de bits
0xC0 conserva los dos bits más significativos para que un programa pueda reconocer el patrón de continuación UTF-8.memcmp
memcmp compara un número fijo de bytes e informa de su orden, comprobando representaciones de almacenamiento en lugar de valores numéricos.memcmp encuentre bytes almacenados diferentes.memcpy
memcpy copia exactamente el número solicitado de bytes entre regiones que no se solapan, sin interpretar los terminadores de cadenas.memcpy(b, a, sizeof a) copia todo el almacenamiento del array a cuando b tiene espacio suficiente y es una región separada.memmove
memmove copia una cantidad solicitada de bytes con comportamiento definido incluso cuando las regiones de origen y destino se solapan.memmove.memset
memset rellena una región con un valor de byte repetido, sin asignar ese valor numérico por separado a cada elemento del array.memset(counts, 0, sizeof counts) pone a cero un array de enteros; el valor de byte 1 no asignaría el entero 1.N
Número de asignaciones realizadas
scanf completó correctamente y se usa para comprobar si los datos solicitados se leyeron realmente.Número de elementos utilizados
O
Orden por filas
grid[0][3] en el almacenamiento de una tabla de cuatro columnas es grid[1][0].P
Parámetro con calificador const
const int a[] porque sumar los valores de entrada no requiere modificarlos.Parámetro de tipo array
int a[] sigue necesitando una longitud separada antes de poder recorrer su entrada con un bucle.Parámetro de tipo modificado variablemente
int g[rows][cols] después de parámetros que definen números de filas y columnas positivos y coincidentes.Puntero al final de la conversión
strtol devuelve 9, pero el puntero al final de la conversión apunta a la z que no se procesó.Puntero nulo
strchr(name, '.') != NULL antes de usar su resultado como inicio de una extensión de archivo.Punto de código Unicode
R
Rango permitido por la aplicación
Reducción modular de enteros sin signo
size_t no puede detenerse al volverse negativa; usa i > 0 y accede a la posición i - 1.S
Secuencia de escape
"A\nB" contiene un salto de línea entre sus letras; la barra invertida y la n codifican un carácter.size_t
size_t es un tipo entero sin signo usado para tamaños de objetos y devuelto por sizeof; se usa habitualmente para longitudes de arrays.printf("%zu", sizeof data) usa el formato de tamaño para imprimir el número de bytes que ocupa data.snprintf
snprintf da formato al texto dentro de una capacidad proporcionada y devuelve la longitud completa del texto necesario o un resultado negativo de error.strcat
strcat añade una cadena de origen en el terminador existente del destino y escribe un nuevo terminador después del texto combinado.strchr
strchr encuentra el primer carácter coincidente en una cadena y devuelve su ubicación, o un puntero nulo si no existe ninguna coincidencia.strchr encuentra la parte final «.part.ext», incluido el primer punto.strcmp
strcmp compara cadenas terminadas en nulo como bytes sin signo y devuelve un resultado negativo, cero o positivo según su orden.strcmp("oak", "oak") == 0 comprueba que el contenido es igual incluso cuando las dos cadenas ocupan almacenamientos separados.strcpy
strcpy copia una cadena de origen completa y su terminador en un destino que no se solapa con ella y tiene suficiente almacenamiento disponible.char out[5].strcspn
strcspn mide la parte inicial de una cadena que no contiene ninguno de los caracteres proporcionados en su segundo argumento.strcspn("fir:oak", ":,") devuelve 3 porque el primer separador indicado aparece después de las tres letras de fir.strlen
strlen recorre una cadena válida hasta su terminador y devuelve el número de bytes anteriores como un valor size_t.char tag[30] = "oak", strlen(tag) es 3, mientras que sizeof tag indica la capacidad completa de 30 bytes.strncat
strncat añade como máximo un número especificado de bytes de texto de origen y después escribe un terminador.strncmp
strncmp compara como máximo un número especificado de bytes de cadenas y se detiene antes si encuentra un final o una diferencia.strncpy
strncpy copia hasta un límite y rellena el texto más corto con ceros, pero no añade un terminador cuando el origen llena ese límite.strrchr
strrchr encuentra el último carácter coincidente en una cadena y devuelve su ubicación, o un puntero nulo si no existe ninguna coincidencia.strrchr puede localizar el separador de la extensión.strtol
strtol convierte texto a long usando una base elegida e informa de la ubicación donde se detuvo y de los errores de rango.strtol(text, &end, 10) permite que el programa rechace una letra restante después de dígitos decimales válidos.Subcadena
strstr encuentra la ubicación inicial de su primera coincidencia.T
Terminador nulo
text[2] = '\0' hace que las funciones de cadenas se detengan después de los dos primeros caracteres de ese array.Transformación en el mismo espacio de almacenamiento
Truncamiento
U
UTF-8
Sobre esta unidad
Crea tus propios Materiales de Estudio
Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.