Debido a que una función strtok pisó un pozo, el viejo ingeniero se burló de mí sin piedad (1)

Seguir, cuenta pública destacada, acceso directo a contenido emocionante

ID: La tecnología hace más grandes los sueños

Autor: Li Xiao Yao

En la realización del corte de cadenas con C / C ++, a menudo se utiliza la función strtok, cuya función principal es separar cadenas de acuerdo con un conjunto de caracteres dado y devolver cada subcadena.

Pero de hecho, no solo existen las funciones strtok (), sino también strtok, strtok_s y strtok_r. Este artículo sirve como un artículo básico para dar una breve introducción. Debido a que abusé de esta función, los viejos ingenieros se burlaron de mí.

Explicación detallada de la función strtok ()

descripción

Esta función se utiliza para dividir una cadena en segmentos y devolver cada subcadena.

Prototipo de función

char *strtok(char *str, const char *delim)

parámetro

  • str, la cuerda a dividir

  • delim, la cadena delimitadora

valor de retorno

Esta función devuelve la primera subcadena que se descompondrá, o un puntero nulo si no hay una cadena recuperable.

Ejemplo

//https://tool.lu/coderunner/
//来源:技术让梦想更伟大
//作者:李肖遥
#include <string.h>
#include <stdio.h>
#define INFO_MAX_SZ 80

int main () {
   char str[INFO_MAX_SZ] = "dream - coder - lixiaoyao";
   const char delim[2] = "-";
   char *token;
   
   //获取第一个子字符串
   token = strtok(str,delim);
   
   //继续获取其他的子字符串
   while( token != NULL ) 
   {
      printf( "%s\n", token );
    
      token = strtok(NULL, delim);
   }
   
   return(0);
}

Los resultados de la operación son los siguientes:

Precauciones

Cuando use esta función para dividir la cadena, destruirá la integridad de la cadena descompuesta, y los s antes y después de la llamada son diferentes. Después de la primera división, la cadena original str es la primera cadena después de que se completa la división, y las cadenas restantes se almacenan en una variable estática.

La función strtok usa un búfer estático cuando extrae la cadena. Por lo tanto, no es seguro para subprocesos. Cuando varios subprocesos acceden a la variable estática al mismo tiempo, se producirá un error. Este artículo es un artículo básico y se analizará con más detalle en el seguimiento.

Expandir un ejemplo de aplicación

Un ejemplo clásico en Internet es dividir una cadena en una estructura, la clasifiqué y miré el código.

//https://tool.lu/coderunner/
//来源:技术让梦想更伟大
//作者:李肖遥

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define INFO_MAX_SZ 80
 
typedef struct person{ 
 char name[25]; 
 char sex[10]; 
 char age[4]; 
}Person;

int main()
{
 int in=0;  
 int j;
 char buffer[INFO_MAX_SZ]="Aob male 18,Bob male 19,Cob female 20";      
 char *p[20];  
 char *buf = buffer;  
 while((p[in]=strtok(buf,","))!=NULL)//先以,为分界符,将三个人的信息分开
 {  
  buf=p[in];//调用strtok,先将子串先一一保存到字符串指针数组中,  
  while((p[in]=strtok(buf," "))!=NULL)//以空格为分界符
  {  
   in++;  
   buf=NULL;  
  }  
  buf=NULL;  
 }  
 printf("Here we have %d strings\n", in);  
 for (j=0; j<in; j++)  
 {  
    //打印指针数组中保存的所有子串
  printf(">%s<\n",p[j]);  
 }  
    return 0;
}

Los resultados son los siguientes

Según este resultado, no obtuvimos el resultado que queríamos, solo se extrajo la información de la primera persona.

¿Entonces, cuál es el problema?

Según nuestro análisis, en el primer ciclo, la función strtok cambia la coma después de la primera información personal a '\ 0. En este momento, el puntero this en strtok apunta al carácter después de la coma.

Después del final del primer ciclo, el primer parámetro de la función se establece en NULL, strtok usará la posición apuntada por este puntero como la posición de inicio de la descomposición, en este momento este puntero apunta a '\ 0', y strtok es un nulo La cadena no se puede dividir y se devuelve NULL, por lo que se obtiene el resultado anterior.

Entonces, ¿cómo resolvemos este problema?

Veamos el código para lograr este resultado deseado.

//https://tool.lu/coderunner/
//来源:技术让梦想更伟大
//作者:李肖遥

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define INFO_MAX_SZ 80
 
typedef struct person{ 
 char name[25]; 
 char sex[10]; 
 char age[4]; 
}Person;

int main()
{
 int in=0;  
 int j;
 char buffer[INFO_MAX_SZ]="Aob male 18,Bob male 19,Cob female 20";      
 char *p[20];  
 char *buf = buffer;  
 while ((p[in] = strtok(buf, " ,")) != NULL)//同时以逗号和空格为分界符
 {  
  switch (in % 3)  
  {  
  case 0:  
   printf("第%d个人:Name!\n", in/3+1);  
   break;  
  case 1:  
   printf("第%d个人:Sex!\n", in/3+1);  
   break;  
  case 2:  
   printf("第%d个人:Age!\n", in/3+1);  
   break;  
  }  
  in++;  
  buf = NULL;  
 }  
 printf("Here we have %d strings\n", in);  
 for (j=0; j<in; j++)  
 {     
  printf(">%s<\n",p[j]);  
 } 
    return 0;
}

El resultado final de la ejecución es el siguiente

Um, ya no puedo ver este tipo de código. Para implementarlo, debemos saber de antemano cuántos miembros de datos están contenidos en una estructura, entonces, ¿existe una función adecuada para reemplazar strtok?

Sí, es strtok_r.

La función strtok_r en Linux

descripción

strtok_r es una versión segura para subprocesos de la función strtok en la plataforma Linux. No está incluido en string.h de windows. Para usar esta función, busque el código fuente de implementación en linux y cópielo en su programa, o use GNU C Library.

La función strtok_r es una versión reentrante de la función strtok. char **saveptrEl parámetro es una char *variable de puntero que se utiliza para almacenar el contexto de segmentación en strtok_r, para resolver la misma cadena fuente en respuesta a llamadas consecutivas.

Al llamar a strtok_r por primera vez, el parámetro str debe apuntar a la cadena que se va a extraer y el valor del parámetro saveptr puede ignorarse. Cuando se llama continuamente, str se le asigna NULL, saveptr es el valor devuelto después de la última llamada, no modificar.

Una serie de cadenas diferentes se pueden llamar continuamente strtok_r para la extracción al mismo tiempo, y se deben pasar diferentes parámetros saveptr para diferentes llamadas.

strtok_r es en realidad el puntero que se guarda implícitamente dentro de strtok, interactuando con el exterior de la función en forma de parámetros. Transferir, guardar e incluso modificar por la persona que llama. Cuando la persona que llama divide continuamente la misma cadena de origen, además de asignar el parámetro str a NULL, también necesita pasar el saveptr guardado durante la última división.

El prototipo de función es el siguiente

char *strtok_r(char *str, const char *delim, char **saveptr);

Código fuente

/* Parse S into tokens separated by characters in DELIM.
   If S is NULL, the saved pointer in SAVE_PTR is used as
   the next starting point.  For example:
        char s[] = "-abc-=-def";
        char *sp;
        x = strtok_r(s, "-", &sp);      // x = "abc", sp = "=-def"
        x = strtok_r(NULL, "-=", &sp);  // x = "def", sp = NULL
        x = strtok_r(NULL, "=", &sp);   // x = NULL
                // s = "abc\0-def\0"
*/
char *strtok_r(char *s, const char *delim, char **save_ptr) {
    char *token;
   /*判断参数s是否为NULL,如果是NULL就以传递进来的save_ptr作为起始分解位置;若不是NULL,则以s开始切分*/
    if (s == NULL) s = *save_ptr;
 
    /* Scan leading delimiters.  */
    s += strspn(s, delim);
    /*判断当前待分解的位置是否为'\0',若是则返回NULL(联系到(一)中所说对返回值为NULL的解释);不是则继续。*/
    if (*s == '\0') 
  return NULL;
 
    /* Find the end of the token.  */
    token = s;
    s = strpbrk(token, delim);
    if (s == NULL)
        /* This token finishes the string.  */
        *save_ptr = strchr(token, '\0');
    else {
        /* Terminate the token and make *SAVE_PTR point past it.  */
        *s = '\0';
        *save_ptr = s + 1;
    }
 
    return token;
}

Darse cuenta del ejemplo anterior

El código que llama a strtok_r tiene dos punteros más que el código que llama a strtok, external_ptr e inner_ptr. external_ptr se usa para marcar la posición de extracción de cada persona, es decir, el bucle externo; inner_ptr se usa para marcar la posición de extracción de cada elemento de información dentro de cada persona, es decir, el bucle interno.

strtok_r muestra el puntero interno original y proporciona el parámetro saveptr. Aumentó la flexibilidad y seguridad de la función.

//https://tool.lu/coderunner/
//来源:技术让梦想更伟大
//作者:李肖遥

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define INFO_MAX_SZ 80
 
typedef struct person{ 
 char name[25]; 
 char sex[10]; 
 char age[4]; 
}Person;

int main()
{
 int in=0;  
 int j;
 char buffer[INFO_MAX_SZ]="Aob male 18,Bob male 19,Cob female 20";      
 char *p[20];  
 char *buf=buffer;  
 char *outer_ptr=NULL;  
 char *inner_ptr=NULL;  
 while((p[in] = strtok_r(buf, ",", &outer_ptr))!=NULL)   
 {  
  buf=p[in];  
  while((p[in]=strtok_r(buf, " ", &inner_ptr))!=NULL)   
  {  
   in++;  
   buf=NULL;  
  }  
  buf=NULL;  
 }  
 printf("Here we have %d strings\n",in);  
 for (j=0; j<in; j++)  
 {     
  printf(">%s<\n",p[j]);  
 } 
    return 0;
}

El resultado de la compilación es el siguiente

Precauciones

Esta función también destruirá la integridad de la cadena descompuesta, pero guarda las cadenas restantes en la variable saveptr para garantizar la seguridad.

La función strtok_s en Windows

descripción

strtok_s es una función de seguridad de cadena dividida en Windows,

prototipo

char *strtok_s( char *strToken, const char *strDelimit, char **buf);
char * strtok_s(char * restrict str,rsize_t * restrict strmax,const char * restrict delim,char ** restrict ptr);

Busque el siguiente token en la cadena de bytes terminada en nulo apuntada por str. El carácter delimitador se identifica mediante la cadena de bytes terminada en nulo a la que apunta delim.

Esta función está diseñada para ser llamada varias veces para obtener tokens consecutivos de la misma cadena.

Puede consultarlo aquí, no hablaré de eso aquí.

https://cloud.tencent.com/developer/p/1009645

Hombros de gigantes

https://blog.csdn.net/bobyangsmile/article/details/38420985

https://www.runoob.com/cprogramming/c-function-strtok.html

Al final

Aquí hay una breve introducción al uso básico de estas funciones y algunas ventajas y desventajas, etc. Más adelante, interpretaré las características ocultas de strtok () de acuerdo con los pozos que pisé ¡Nos vemos en el próximo número!

Lectura recomendada:

嵌入式编程专辑Linux 学习专辑C/C++编程专辑

关注微信公众号『技术让梦想更伟大』,后台回复“m”查看更多内容,回复“加群”加入技术交流群。
长按前往图中包含的公众号关注

Supongo que te gusta

Origin blog.csdn.net/u012846795/article/details/107903402
Recomendado
Clasificación