2009-05-01 6 views

Respuesta

41

Es equivalente a esto:

while (*t) { 
    *s = *t; 
    s++; 
    t++; 
} 
*s = *t; 

Cuando el carbón de leña que t puntos a es '\0', el bucle while terminará. Hasta entonces, copiará el carácter que t está apuntando al carácter que apunta s, luego incremente s y t para apuntar al siguiente carácter en sus matrices.

+3

Consulte mi respuesta a continuación. Esta respuesta es incorrecta –

-1

Sí, tiene que ver con los punteros.

La forma de leer el código es la siguiente: "el valor que apunta el puntero" s "(que se incrementa después de esta operación) obtiene el valor señalado por el puntero" t "(que obtiene incrementado después de esta operación; el valor total de esta operación se evalúa con el valor del carácter copiado; itere a través de esta operación hasta que ese valor sea igual a cero. "Dado que el valor del terminador nulo de cadena es el valor del carácter cero ('/ 0'), el ciclo repetirá hasta que una cadena se copie desde la ubicación apuntada por t a la ubicación apuntada por s.

0

copia una cadena porque las matrices siempre se pasan por referencia, y la cadena es solo una matriz char. Básicamente, lo que está sucediendo es (si mal no recuerdo el término) aritmética del puntero. ere's a bit more information from wikipedia on c arrays.

Está almacenando el valor desreferenciado de t en s y luego pasando al siguiente índice a través de ++.

1

Funciona mediante la copia de caracteres de la cadena apuntada por 't' en la cadena apuntada por 's'. Para cada copia de personaje, ambos punteros se incrementan. El ciclo termina cuando encuentra un carácter NUL (igual a cero, de ahí la salida).

-1

Sí, esto utiliza punteros, y también hace todo el trabajo mientras se evalúa la condición de tiempo. C permite que las expresiones condicionales tengan efectos secundarios.

El operador "*" deja de marcar los punteros s y t.

El operador de incremento ("++") incrementa los punteros s y t después de la asignación.

El ciclo termina con la condición de un carácter nulo, lo que se evalúa como falsa en C.

Un comentario adicional .... esto no es código seguro, ya que no hace nada para garantizar s ha asignado suficiente memoria.

1

CONSEJOS:

  • Lo que hace el operador '=' hacer?
  • ¿Cuál es el valor de la expresión "a = b"? Ej .: si haces "c = a = b" ¿qué valor obtiene c?
  • ¿Qué termina una cadena en C? ¿Evalúa verdadero o falso?
  • En "* s ++", ¿qué operador tiene mayor prioridad?

CONSEJO:

  • Uso strncpy() en su lugar.
0

Digamos que tiene algo como esto:

char *someString = "Hello, World!"; 

someString puntos para el primer carácter de la cadena - en este caso, 'H'.

Ahora, si se incrementa el puntero por uno:

someString++ 

someString ahora apuntará a 'e'.

while (*someString++); 

bucle voluntad hasta que sea someString puntos en los convierte en NULL, que es lo que señala el final de una cadena ("terminada en nulo").

Y el código:

while (*s++ = *t++); 

es igual a:

while (*t != NULL) { // While whatever t points to isn't NULL 
    *s = *t;   // copy whatever t points to into s 
    s++; 
    t++; 
} 
26

Esto tiene mucho pasando bajo las sábanas:

while (*s++ = *t++); 

El s y t variables son punteros (casi con certeza personajes), siendo el destino el s. Los pasos siguientes ilustran lo que está sucediendo:

  • los contenidos de t (*t) se copian en s (*s), un carácter.
  • s y t ambos se incrementan (++).
  • la asignación (copia) devuelve el carácter que se copió (al while).
  • while continúa hasta que el carácter sea cero (fin de cadena en C).

Efectivamente, es:

while (*t != 0) { 
    *s = *t; 
    s++; 
    t++; 
} 
*s = *t; 
s++; 
t++; 

pero escrito a cabo de una forma mucho más compacta.

3

El aspecto misterioso de esto es el orden de las operaciones.Si se mira la especificación del lenguaje C, que establece que, en este contexto, el orden de las operaciones es la siguiente:

1. * operator 
2. = (assignment) operator 
3. ++ operator 

Así que el bucle while se convierte entonces, en Inglés:

 
while (some condition): 
    Take what is at address "t" and copy it over to location at address "s". 
    Increment "s" by one address location. 
    Increment "t" by one address location. 

Ahora, ¿Qué es "alguna condición"? La especificación Clang también dice que el valor de una expresión de asignación es el valor asignado en sí mismo, que en este caso es *t.

Así que "alguna condición" es "t apunta a algo que no es cero", o de una manera más simple "mientras que los datos de ubicación no es tNULL".

+0

por qué la asignación se realiza antes del operador de incremento de publicación cuando el operador de incremento de publicación tiene mayor prioridad. – light

-1

comienza un bucle while ....

* S = * t va primero, este asigna a lo t puntos al a lo s puntos al. es decir, copia un carácter de una cadena a una cadena.

lo que se está asignando se pasa a la condición de tiempo ... cualquier valor distinto de cero es "verdadero", por lo que continuará, y 0 es falso, se detendrá ... y ocurre el final de una cadena también es cero.

s ++ y t ++ que se incrementan los punteros

y todo comienza de nuevo

por lo que mantiene la asignación de bucle, moviendo los punteros, hasta que choca con un 0, que es el final de la cadena

17

Supongamos que s y t son char * s que apuntan a cadenas (y supongamos que s es al menos tan grande como t). En C, todas las cadenas terminan en 0 (ASCII "NUL"), ¿correcto? Entonces, ¿qué hace esto:

*s++ = *t++; 

primer lugar, se hace *s = *t, copiando el valor en *t-*s. Luego, hace s++, por lo que s ahora apunta al siguiente carácter. Y luego lo hace t++, por lo que t apunta al siguiente carácter. Esto tiene que ver con el precedencia de operador y el prefijo frente al incremento/decremento de posfijo.

La precedencia del operador es el orden en que se resuelven los operadores. Para un ejemplo sencillo, mira:

4 + 2 * 3 

¿Es esta 4 + (2 * 3) o (4 + 2) * 3? Bueno, sabemos que es el primero debido a precedence - el * binario (operador de multiplicación) tiene una precedencia mayor que el + binario (operador adicional), y se resuelve primero.

En *s++, tenemos unario * (operador de referencia a un puntero) y unario ++ (operador de incremento de sufijo). En este caso, ++ tiene una precedencia más alta (también se dice que "se unen más estrictamente") que *.Si hubiéramos dicho ++*s, queremos incrementar el valor en*s en lugar de la dirección de apuntado pors porque prefijo incremento tiene menor precedencia * como eliminar la referencia, pero utilizamos postfix de la subasta, que tiene mayor precedencia. Si hubiéramos querido usar el incremento de prefijo, podríamos haber hecho *(++s), ya que el paréntesis habría anulado todos los precedentes más bajos y forzado a ++s como primero, pero esto tendría el efecto secundario indeseable de dejar un carácter vacío al comienzo de la cadena .

Tenga en cuenta que solo porque tiene una mayor prioridad no significa que suceda primero. El incremento de Postfix sucede específicamente después de el valor se ha utilizado, que su *s = *t ocurre antes de s++.

Así que ahora entiendes *s++ = *t++. Pero lo ponen en un bucle:

while(*s++ = *t++); 

Este bucle hace nada - la acción es todo en la condición. Pero revisa esa condición: devuelve "falso" si *s es alguna vez 0, lo que significa que *t fue 0, lo que significa que estaban al final de la cadena (yay para ASCII "NUL"). Así que este bucle se bifurca mientras haya caracteres en t, y los copia diligentemente en s, incrementando s y t hasta el final. Cuando este ciclo sale, s ha terminado con NUL, y es una cadena adecuada. El único problema es s puntos hasta el final. Mantenga otro puntero práctica que apunta al comienzo de s (es decir s antes del bucle while()) - que será su cadena de copiado:

char *s, *string = s; 
while(*s++ = *t++); 
printf("%s", string); // prints the string that was in *t 

Alternativamente, mira esto:

size_t i = strlen(t); 
while(*s++ = *t++); 
s -= i + 1; 
printf("%s\n", s); // prints the string that was in *t 

Nosotros Comenzamos por obtener la longitud, así que cuando terminamos, hicimos más aritmética de punteros para poner s al principio, donde comenzó.

Por supuesto, este fragmento de código (y todos mis fragmentos de código) ignoran los problemas del búfer por simplicidad. La mejor versión es la siguiente:

size_t i = strlen(t); 
char *c = malloc(i + 1); 
while(*s++ = *t++); 
s -= i + 1; 
printf("%s\n", s); // prints the string that was in *t 
free(c); 

Pero ya lo sabías, o pronto harás una pregunta en el sitio web favorito de todos sobre ella. ;)

* En realidad, tienen la misma precedencia, pero eso se resuelve con reglas diferentes. Ellos efectivamente tienen menor precedencia en esta situación.

+0

¿Alguien puede ayudarme a explicar por qué 'char * c = malloc (i + 1);' y 'libre (c);' es mejor 'ignorar los problemas del búfer por simplicidad'? No lo entiendo –

1

el lenguaje C de programación (K & R) por Brian W. Kernighan y Dennis M. Ritchie da una explicación detallada de esto.

segunda edición, página 104:

5.5 punteros a carácter y funciones

A constante de cadena, escrito como

"I am a string" 

es un array de caracteres. En la representación interna, la matriz finaliza con el carácter nulo '\0' para que los programas puedan encontrar el final. La longitud de almacenamiento es, por lo tanto, uno más que el número de caracteres entre las comillas dobles.

Tal vez el caso más común de las constantes de cadena es como argumentos a funciones, como en

printf("hello, world\n"); 

Cuando una cadena de caracteres como éste aparece en un programa, el acceso a ella es a través de un puntero de carácter; printf recibe un puntero al comienzo de la matriz de caracteres. Es decir, se accede a una constante de cadena mediante un puntero a su primer elemento.

Las constantes de cadena no necesitan ser argumentos de funciones. Si pmessage está declarada como

char *pmessage; 

entonces la declaración

pmessage = "now is the time"; 

asigna a pmessage un puntero a la matriz de caracteres. Esto es no una copia de cadena; solo punteros están involucrados. C no proporciona operadores para procesar una cadena completa de caracteres como una unidad.

Hay una diferente importante entre estas definiciones:

char amessage[] = "now is the time"; /* an array */ 
char *pmessage = "now is the time"; /* a pointer */ 

amessage es una matriz, lo suficientemente grande para contener la secuencia de caracteres y '\0' que lo inicializa. Los caracteres individuales dentro de la matriz pueden cambiarse por amessage siempre se referirán al mismo almacenamiento. Por otro lado, pmessage es un puntero, inicializado para apuntar a una constante de cadena; el puntero puede modificarse posteriormente para apuntar a otro lugar, pero el resultado no está definido si intenta modificar los contenidos de la cadena.

  +---+  +--------------------+ 
pmessage: | o-------->| now is the time \0 | 
      +---+  +--------------------+ 

      +--------------------+ 
amessage: | now is the time \0 | 
      +--------------------+ 

Ilustraremos más aspectos de punteros y matrices estudiando las versiones de dos funciones útiles adaptadas de la biblioteca estándar. La primera función es strcpy(s,t), que copia la cadena t en la cadena s. Sería bueno simplemente decir s = t pero esto copia el puntero, no los caracteres. Para copiar los caracteres, necesitamos un ciclo. La versión de matriz es primero:

/* strcpy: copy t to s; array subscript version */ 
void strcpy(char *s, char *t) 
{ 
    int i; 

    i = 0; 
    while((s[i] = t[i]) != '\0') 
     i ++; 
} 

Por el contrario, aquí es una versión de strcpy con punteros:

/* strcpy: copy t to s; pointer version 1 */ 
void strcpy(char *s, char *t) 
{ 
    while((*s = *t) != '\0') 
    { 
     s ++; 
     t ++; 
    } 
} 

porque los argumentos se pasan por valor, strcpy puede usar los parámetros s y t en modo alguno eso agrada. Aquí están los punteros convenientemente inicializados, que se marchan a lo largo de las matrices un carácter a la vez, hasta que '\0' que termina t se haya copiado al s.

En la práctica, strcpy no estaría escrito como lo mostramos arriba. Experimentados programadores de C preferirían

/* strcpy: copy t to s; pointer version 2 */ 
void strcpy(char *s, char *t) 
{ 
    while((*s++ = *t++) != '\0') 
     ; 
} 

Esto mueve el incremento de s y t en la parte de la prueba del bucle. El valor de *t++ es el carácter que se incrementó en t antes de t; el postfijo ++ no cambia t hasta después de que se haya obtenido este caracter. De la misma manera, el carácter se almacena en la antigua posición s antes de que se incremente s. Este caracter también es el valor que se compara con '\0' para controlar el ciclo. El efecto neto es que los caracteres se copian de t a s, hasta e incluyendo la terminación '\0'.

Como abreviatura final, observe que una comparación contra '\0' es redundante, ya que la pregunta es simplemente si la expresión es cero. Por lo tanto la función es probable que se escribe como

/* strcpy: cope t to s; pointer version 3 */ 
void strcpy(char *s, char *t) 
{ 
    while(*s++ = *t++); 
} 

Aunque esto puede parecer críptico primera vista, la conveniencia de notación es considerable, y el lenguaje debe ser dominado, porque verá si con frecuencia en programas C.

El strcpy en la biblioteca estándar (<string.h>) devuelve la cadena de destino como su valor de función.

Éste es el final de las partes pertinentes de esta sección.

PD: Si le gustó leer esto, considere comprar una copia de K & R - no es caro.

12
while(*s++ = *t++); 

¿Por qué la gente piensa que es equivalente a:

while (*t) { 
    *s = *t; 
    s++; 
    t++; 
} 
*s = *t; /* if *t was 0 at the beginning s and t are not incremented */ 

cuando obviamente no lo es.

char tmp = 0; 
do { 
    tmp = *t; 
    *s = tmp; 
    s++; 
    t++; 
} while(tmp); 

es más como él

EDIT: Se ha corregido un error de compilación. La variable tmp debe declararse fuera del ciclo.

+2

Buena captura ... se copia al menos una vez. – baash05

-1

La pregunta que proporcioné la siguiente respuesta se cerró como un duplicado de esta pregunta, por lo que estoy copiando la parte relevante de la respuesta aquí.

La explicación semántica real del bucle while sería algo así como:

for (;;) { 
    char *olds = s;    // original s in olds 
    char *oldt = t;    // original t in oldt 
    char c = *oldt;    // original *t in c 
    s += 1;      // complete post increment of s 
    t += 1;      // complete post increment of t 
    *olds = c;     // copy character c into *olds 
    if (c) continue;   // continue if c is not 0 
    break;      // otherwise loop ends 
} 

El orden en que s y t se salvan, y el orden en que s y t se incrementan pueden intercambiarse. El guardado de *oldt a c puede ocurrir en cualquier momento después de que se guarde oldt y antes de que se use c.La asignación de c a *olds puede ocurrir en cualquier momento después de que se guardan c y olds. En el reverso de mi sobre, funciona con al menos 40 interpretaciones diferentes.

+0

Esta respuesta se canceló porque está respondiendo [la pregunta que se marcó como duplicada] (http://stackoverflow.com/q/16581048/315052). Al mismo tiempo, responde a esta pregunta sobre cómo ocurre la copia. – jxh

-2

Bueno, esto es cierto solo en el caso de la char si no hay \ 0 y la matriz es entera, el programa se bloqueará porque habrá una dirección cuyos elementos no son la parte de la matriz o puntero , si el sistema tiene memoria asignada usando malloc, el sistema seguirá dando la memoria

Cuestiones relacionadas