Usando printf con una cadena terminada no nula

107

Suponga que tiene una cadena que NO está nullterminada y conoce su tamaño exacto, entonces, ¿cómo puede imprimir esa cadena printfen C? Recuerdo tal método pero no puedo averiguarlo ahora ...

quien yo
fuente
9
En Ccontexto, todas las cadenas terminan en nulo. Las matrices de char sin un nulo en ellas no son cadenas ... son matrices de char :)
pmg
stackoverflow.com/questions/2239519/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

174

Existe una posibilidad con printf, es así:

printf("%.*s", stringLength, pointerToString);

No es necesario copiar nada, no es necesario modificar la cadena o el búfer original.

DarkDust
fuente
10
Pero de todos modos es peligroso, alguien algún día imprimirá esta cadena con% s
pmod
6
@Pmod: no necesariamente si el búfer no está expuesto al mundo exterior. También es muy útil simplemente imprimir partes de una cadena (que puede tener terminación nula, por supuesto). Si realmente desea ver esto en acción, eche un vistazo al proxy SIP de OpenSER / Kamailio donde evitan copiar mucho debido a esta técnica (también usando sprintf).
DarkDust
6
otro +1. Me encanta cuando aprendo cosas básicas, printfincluso después de una ~ década ... :)
Hertzel Guinness
1
Para mí es muy útil cuando recibo una cadena terminada no nula de una API (¡algunas API de Windows hacen esto!) Y tengo que devolverla de una manera 'razonable'. Entonces: ¡larga vida a%. * S (o%. * S que también hará la conversión UNICODE <-> SINGLE-BYTE para usted!;))
FrizzTheSnail
3
@ user1424739: En su caso printf, imprimirá hasta 11 caracteres o hasta que encuentre NULL, lo que ocurra primero; en su ejemplo, NULL viene primero. Especificar una longitud máxima no hace que NULL pierda su significado de "fin de cadena" para printf.
DarkDust
29

Aquí hay una explicación de cómo %.*sfunciona y dónde se especifica.

Las especificaciones de conversión en una cadena de plantilla printf tienen la forma general:

% [ param-no $] flags width [ . precision ] type conversion

o

% [ param-no $] flags width . * [ param-no $] type conversion

La segunda forma es para obtener la precisión de la lista de argumentos:

También puede especificar una precisión de '*'. Esto significa que el siguiente argumento en la lista de argumentos (antes del valor real que se imprimirá) se utiliza como precisión. El valor debe ser un int y se ignora si es negativo.

Sintaxis de conversión de salida en el manual de glibc

Para el %sformato de cadenas, la precisión tiene un significado especial:

Se puede especificar una precisión para indicar el número máximo de caracteres a escribir; de lo contrario, los caracteres de la cadena hasta pero sin incluir el carácter nulo de terminación se escriben en el flujo de salida.

Otras conversiones de salida en el manual de glibc

Otras variantes útiles:

  • "%*.*s", maxlen, maxlen, val justificará a la derecha, insertando espacios antes;
  • "%-*.*s", maxlen, maxlen, val justificará a la izquierda.
Tobu
fuente
Si lo entiendo correctamente, lo siguiente rellenaría la salida y aún así evitaría un desbordamiento de cadena. "%-*.*s", padding, str_view.size(), str_view.data()
scx
20

¡Puede usar un fwrite () para stdout!

fwrite(your_string, sizeof(char), number_of_chars, stdout);

De esta manera, generará los primeros caracteres (número definido en la variable number_of_chars) a un archivo, en este caso a stdout (la salida estándar, su pantalla).

Pedro Sousa
fuente
2
¡Muy útil cuando desea inspeccionar un búfer largo que contiene cadenas y ceros!
Elist
13

printf("%.*s", length, string) no trabajará.

Esto significa imprimir HASTA bytes de longitud O un byte nulo, lo que ocurra primero. Si su matriz de caracteres no terminada en nulo contiene bytes nulos ANTES de la longitud, printf se detendrá en ellos y no continuará.

Todd liberado
fuente
4
¿Y cómo es esto una respuesta a la pregunta del OP?
Shahbaz
12
si no está terminado en nulo, entonces nulo es un carácter válido para que la cadena lo contenga. esto todavía piensa que la matriz está terminada en nulo, simplemente la trata como una matriz más larga de la que está sub-seleccionando, lo que significa que si tiene una cadena con nulos, esto causará problemas.
lahwran
3
printf("%.5s", pointerToNonNullTerminatedString);

La longitud de la cuerda será 5.

codeDom
fuente
1
#include<string.h> 
int main()
{
/*suppose a string str which is not null terminated and n is its length*/
 int i;
 for(i=0;i<n;i++)
 {
 printf("%c",str[i]);
 }
 return 0;
}

Edité el código, aquí hay otra forma:

#include<stdio.h>
int main()
{
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/

return 0;

}
fuddin
fuente
Muy mal rendimiento debido a una gran cantidad de lecturas de bytes innecesarias (que vienen con una penalización de rendimiento si el byte no está en una dirección alineada con la palabra en la mayoría de las CPU) y también se realiza el análisis y la aplicación del formato para todos y cada uno de los caracteres. No hagas eso :-) Mira mi respuesta para la solución.
DarkDust
@DarkDust: solo una máquina patológica penalizaría las lecturas de bytes que no estén alineadas con los límites de las palabras. ¿Estás pensando en lecturas de palabras que no están alineadas con los límites de las palabras? ¿O alguna mierda antigua de mips o algo así?
R .. GitHub DEJA DE AYUDAR A ICE
@R ..: Si consideras que x86 tiene daño cerebral y está desactualizado, estoy absolutamente de acuerdo. Porque x86 tiene una penalización por leer y escribir memoria no alineada con palabras. También ARM. Vea, por ejemplo, esta pregunta o esta pregunta . La cuestión es (si lo entendí correctamente) que los datos se obtienen en trozos del tamaño de una palabra de la memoria y obtener el byte correcto es otro micro-op. No es gran cosa, pero en un gran bucle podría marcar la diferencia.
DarkDust
@DarkDust: estás completamente equivocado al respecto para las lecturas de bytes. ¿Por qué no haces un benchmark? x86 tiene operaciones de bytes completamente atómicas y siempre las tuvo. No recupera fragmentos del tamaño de una palabra (excepto en el nivel de caché, que obtiene fragmentos mucho más grandes y la alineación es irrelevante, pero estoy hablando de datos ya almacenados en caché).
R .. GitHub DEJA DE AYUDAR A ICE
@DarkDust: PS3 no admite lectura o escritura de bytes no alineados en SPU. De hecho, ni siquiera admite tipos escalares, solo hay vectores, que deben estar alineados. El compilador los emula. Y muchos procesadores ARM no admiten lectura o escritura de bytes, sino que solo realizan lectura o escritura de palabras.
Sylvain Defresne