六、C指针(1)

本文详细介绍了C语言中的指针概念、基础知识及其与数组、函数的关系,并深入探讨了指针与字符串的操作技巧,包括指针匹配、大小、空指针及野指针等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一章 指针

1 指针概述

1.1 内存概述

在这里插入图片描述
指针:内存的编号

1.2 指针和指针变量

  • 内存区的每一个字节都有一个编号,这就是“地址”。
  • 如果在程序中定义了一个变量,在对程序进行编译或运行时,系统就会给这个变量分配内存单元,并确定它的内存地址(编号)
  • 指针的实质就是内存“地址”。指针就是地址,地址就是指针
  • 指针是内存单元的编号,指针变量是存放地址的变量
  • 通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样。

32位系统中:0x0000 0000,一个地址用32位表示,即4字节,指针变量占4字节
64位系统中:内存的编号范围是0x0000000000000000 - oxffffffffffffffff ,这样的编号,需要8个字节才能存下,所以指针变量也需要8个字节

在这里插入图片描述

2 指针基础知识

2.1 指针变量的定义和初始化

  • 指针也是一种数据类型,指针变量也是一种变量
  • 指针变量指向谁,就把谁的地址赋值给指针变量
  • “*”操作符操作的是指针变量指向的内存空间

定义指针的三步骤:

int a = 10;
1  *与符号结合代表是一个指针变量
2  要保存谁的地址,将他的定义形式放在此处       
3*p替换掉定义的变量
int a  --->   int (*p)   --->   int *p
int *p = &a;

分析:

1 p是变量名,值是内存地址
  p的类型为:将变量p隐藏剩下的,即在本例中为int *类型
2 指针变量p用来保存什么类型数据的地址:
	将指针变量p和离p最近的*一起隐藏
	在本例中: int *p  ---->  int :即该指针变量保存int类型数据的地址

使用时:*与p结合代表,取p指针所指向那块空间的内容

*p = 100;

在这里插入图片描述
注意:&可以取得一个变量在内存中的地址。但是,不能取寄存器变量,因为寄存器变量不在内存里,而在CPU里面,所以是没有地址的。

2.1.1 关于指针匹配问题

有时候会保存多级的地址,int*p, int **q, *q = &p等,很容易搞错。
下面介绍一个原则:
=在使用时,对一个表达式取 *,就会对表达式减一级 *,如果对表达式取&,就会加一级 *=
在这里插入图片描述
在这里插入图片描述

2.2 指针大小

  • 使用sizeof()测量指针的大小,得到的总是:4或8
  • sizeof()测的是指针变量指向存储地址的大小
  • 在32位平台,所有的指针(地址)都是32位(4字节)
  • 在64位平台,所有的指针(地址)都是64位(8字节)
int *p1;
int **p2;
char *p3;
char **p4;
printf("sizeof(p1) = %d\n", sizeof(p1));
printf("sizeof(p2) = %d\n", sizeof(p2));
printf("sizeof(p3) = %d\n", sizeof(p3));
printf("sizeof(p4) = %d\n", sizeof(p4));
printf("sizeof(double *) = %d\n", sizeof(double *));

指针变量只用来保存地址,不管有多少级,指针地址都是4字节或8字节

不同类型的指针变量, 取指针指向的内容的宽度

指针的宽度 = sizeof(将指针变量与指针变量最近的*隐藏,剩下的类型) 
宽度也叫做步长; 
步长:  指针加1跨过多少个字节
char  *p       1 
short *p       2
int    *p      4
Int  **p       4    sizeof(int *)   
int main()
{
   int  num = 0x01020304;
   char  *p1 = (char *)#//int *
   short *p2 = (short *)#
   int *p3 = #
   //通过*取指针变量所指向那块空间内容时,取的内存的宽度和指针变量本身的类型有关
   printf("%x\n",*p1);
   printf("%x\n", *p2);
   printf("%x\n", *p3);
   system("pause");
   return 0;
}

在这里插入图片描述
在这里插入图片描述

2.3 野指针与空指针

野指针就是没有初始化的指针,指针的指向是随机的,不可以 操作野指针。
此指针指向的区域是未知(操作系统不允许操作此指针指向的内存区域)。所以,野指针不会直接引发错误,操作野指针指向的内存区域才会出问题

//野指针
int main()
{
	 int  *p;//野指针 
	 *p = 200;
	 printf("%d\n",*p);
	 system("pause");
	 return 0;
}

空指针:把NULL赋值给此指针,这样就标志此指针为空指针,没有任何指针。

int main()
{
    int  a;
    //将指针的值赋值为0,0x0000000 =  NULL
    //赋值为null只是一个标志,代表此指针还没被使用
    int  *p = NULL;//给指针p的内容赋值为0
    
    *p = 200;//err  因为p保存了0x0000的地址,这个地址是不可以使用的,非法,
    
    printf("%d\n",*p);
    system("pause");
    return 0;
}

空指针的作用: 如果使用完指针将指针赋值为NULL,在使用时判断一下指针是否为NULL,就知道指针有没有被使用

2.4 万能指针void *

可以保存任意变量的地址
说明:
void * 可以保存所有类型的地址,
但是用该指针(通过地址)去取值的时候,由于void不知道取多少字节,所以无法取值
解决:
需要强转给指定的步长(sizeof)去寻址取值。

//万能指针
int main()
{
     //void b; 不可以定义void类型的变量,因为编译器不知道给变量分配多大的空间
     //但是可以定义void *类型,因为指针都是4个字节
     int  a = 10;
     short b = 10;
     void *p = (void *)&a;//万能指针可以保存任意的地址,为了保持前后统一,进行强转
     void  *q = (void *)&b;
     //printf("%d\n", *p);//err  p是void*,不知道取几个字节的大小,无法根据地址取值
     printf("%d\n",* (int *)p);// 先把地址转为int *类型,再取值,即*(  (int *)地址)
     system("pause");
     return 0;
}

2.5 const修饰的指针变量

const修饰的普通数据类型变量,不能通过变量名修改,可以通过它的地址去修改

const int c = 10;
int *p = &c;
*p = 100;

const修饰指针变量:
1 指向内容不能改变
2 指向不能改变
3 都不能改变

int main()
{
    int  a = 10;
    int  b = 20;
    //const修饰的是 * 还是变量p,
    
    //const修饰的是*    
    //const int  *p = &a; //不能通过 *p,改p所指向空间的内容
    //*p = 100; // err 指向空间内容不能改变
    
    //const修饰的变量p
    //p保存的地址不可以修改
    //int  * const p = &a;
    //p = &b;err  p本身的值不能被更改
    
    const  int *const p = &a; //不能通过*p修改指向空间内容,且不能改变p指向
    system("pause");
    return 0;
}

2.6 多级指针

定义多级指针保存数据的地址时,定义的指针的类型只需要比要保持的数据的类型多一级*
在这里插入图片描述

//多级指针
int main()
{       
    int a = 10;
    //*p  int a     int *p
    int *p = &a;
    //*q  int *p   int **q
    int **q = &p;
    //如果*和&相遇,相抵消
    // **q == *(*q) == *(p) ==  a
    //**q == *(*q) == *(&a) ==  a
    printf("%d\n", **q);
    // *k  int **q  int ***k
    int ***k = &q;
    //*符号结合,代表这个k是一个指针变量
    //k是一个变量
    //k的类型,将变量k隐藏,剩下的类型
    //k用来保存谁的地址  将变量k和k最近的*一起隐藏,剩下什么类型
    //就保存什么类型数据的地址
    int *******************g;
    int ********************f = &g;
    system("pause");
    return 0;
}

3 指针与数组

3.1 数组名

数组名字是数组的首元素地址,但它是一个常量

int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
printf("a = %p\n", a);
printf("&a[0] = %p\n", &a[0]);

//a = 10; //err, 数组名只是常量,不能修改

3.2 指针操作数组元素

数组名a即数组的地址不可以改变,但是使用指针就可以指向数组某个元素

int main()
{
   //int  a[10] = {1,2,3,4,5,6,7,8,9,10};
   int  a[10] = { 0 };
   //a 数组名,首元素的地址
   int  *p = a;//指针p保存的是首元素的地址
   for (int i=0;i<sizeof(a)/sizeof(a[0]);i++)
   {
          //printf("%d ",a[i]);
          //printf("%d ", *(p+i));
          *(p + i) = i;
   }
   for (int i = 0; i<sizeof(a) / sizeof(a[0]); i++)
   {
          printf("%d ",a[i]);
          //printf("%d ", *(p+i));
          //*(p + i) = i;
   }
   system("pause");
   return 0;
}

指针加1,跨过一个步长

int  *p; 
步长  =  sizeof(int)
步长  =  sizeof(将p和最近的*隐藏即为步长)

要得到内存的数据,就该先得到数据的地址
*(地址) 得到的是地址里面的内容

3.3 指针加减运算

加法:两指针相加没有意义,只限跨步长的加法

  • 如果是一个int *,+1的结果是增加一个int的大小
  • 如果是一个char *,+1的结果是增加一个char大小

两指针(类型一致)相减,得到的是中间跨过多少元素

int main()
{
    int  a[10] = {1,2,3,4,5,6,7,8,9,10};
    //sizeof(int [10])
    int *p = a;
    //int  *q = (int *)(&a + 1) - 1;
    int  *q = &a[9];
    printf("%d\n",q-p);//  p+9 ==  q
    printf("%d\n",*(p+3));
    //两指针相加没有意义
    // printf("%d\n", p+q);err
    system("pause");
    return 0;
}

tips:

int *q = (int *)(&a + 1) - 1;
&a + 1代表跨过整个数组
要想指针指向数组末尾元素,必须向前跨一个元素,但是直接减一是向前跨整个元素
所以需要根据数组的元素类型,先转为int*指定步长后,再向前减一移动一个元素的长度

3.4 [] == *()

p[i] == *(p+i)

int main()
{
   //[] == *()
   int  a[10] = { 1,2,3,4,5,6,7,8,9,10 };
   int *p = a;
   for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
   {
          //printf("%d ",a[i]);//a[i] == *(a+i)
          //printf("%d ", *(p+i));
          //printf("%d ", p[i]);// p[i]  == *(p+i)
          printf("%d ", *(a + i));
   }
   system("pause");
   return 0;
}

3.5 指针数组

指针数组,它是数组,数组的每个元素都是指针类型。

int main()
{
   int a = 10;
   int b = 20;
   int c = 30;
   // int *p1 = &a  int *p2 = &a  int *p2 = &a
   //需求:  数组中的每一个元素都是指针(地址)
   int *num[3] = {&a,&b,&c};
   printf("%d\n",sizeof(num));
   //&a  ==  num[0]
   for(int i=0;i<sizeof(num)/sizeof(num[0]);i++)
   {
   //先通过下标取到地址 num[i],再*取值 *num[i]
     printf("%d\n",*num[i]);
   }
   
   system("pause");
   return 0;
}

定义一个指针用来保存数组num首元素的地址:

1 num[0]是int* 类型
2 用指针保存则定义int *k
3 将int *k替换 num[0] 则:int **类型
int main()
{
     int a = 10;
     int b = 20;
     int c = 30;
     int *num[3] = {&a,&b,&c};
     //定义一个指针用来保存数组num首元素的地址
     // num ==  &num[0] =   &(int *)  == int **
     //num[0]是int *类型,要保持int  *类型的地址,需要比它多一级*
     int **k = num;
     for (int i = 0; i < sizeof(num) / sizeof(num[0]); i++)
     {
            printf("%d ",**(k+i));
     }
     
     system("pause");
     return 0;
}

在这里插入图片描述
第一级*:取值取到的仍然是地址
第二级*:取到值

4 指针和函数

4.1 指针作为函数的形参

值传递,只改变传递后的形参的值,作用的是形参,并未与实参建立任何联系。
在这里插入图片描述

指针作为函数的形参,可以改变实参的值,形参拿到是实参的地址,根据地址直接取实参内存空间的里的值操作
在这里插入图片描述

4.2 数组名做函数参数

数组作为函数的形参会退化为指针
如:int b[10] === int *b
另外只传数组名相当于只初始化了一个指针,并不能知道数组的长度,需要将长度传给函数

//void print_arr(int b[10]) // int  *b
//void print_arr(int b[1000])//int  *b
void print_arr(int *b,int  len)
{
    int  n = sizeof(b) / sizeof(b[0]);  // *(b+0)  == *b
    printf("n=%d\n",n);
    for (int i = 0; i <len; i++)
    {
        printf("%d ",b[i]);
    }
    printf("\n");
}
int main()
{
   int  a[10] = { 1,2,3,4,5,6,7,8,9,10 };
   print_arr(a,sizeof(a)/sizeof(a[0]));//打印数值的内容//  &a[0]   int *
   system("pause");
   return 0;
}

4.3 指针作为函数的返回值

int num = 0;//在函数外面定义的变量叫全局变量,整个工程都可以使用
//整个变量程序启动开辟空间,直到程序结束释放空间
int * getnum()
{
   //{}中定义的变量叫局部变量,局部变量在函数结束之后的空间会被释放
   srand(time(NULL));
   num = rand();
   return &num;//
}
int main()
{
   int * p = getnum();
   printf("%d\n",*p);
   system("pause");
}    

以上如果 不把num定义为全局变量,那么getnum函数执行完就销毁了,这时候拿到num的地址是没有意义的,因为num内存空间已经被销毁了。

5 指针和字符串

5.1 字符指针

int main()
{
   //指针与字符串
   char  a[] = "helloworld";//定义了一个字符数组,字符数组内容为helloworld\0
   //定义一个指针用来保存数组首元素的地址
   char  * p = a;
   printf("%s\n",p);//%s打印一个字符串,要的是首个字符的地址
   printf("%s\n", p + 2);
   printf("%c\n",*(p+3));
   *p = 'm';
   printf("%s\n", p);
   //a++
   p++;
   *p = 'o';
   printf("%s\n", p);
   //printf("%d\n",sizeof(a));//11
   //printf("%d\n", sizeof(p));//4
   //printf("%d\n", strlen(a));//
   //printf("%d\n", strlen(p));//
   system("pause");
   return 0;
}

5.2 字符串常量

“hello” 字符串常量是不可以改变的,存在文字常量区
在使用时.双引号""代表取这个字符串首元素的地址
char *p = “hello”; //代表将字符串常量的地址赋值给指针p

int main()
{
   char  a[] = "helloworld";//定义了一个字符数组,字符数组内容为helloworld
                                                 
   char  * p = a;//定义一个指针用来保存数组首元素的地址
   p = "abcdef";//字符串常量存文字常量区,""在使用时,取的是字符串首元素的地址
   //文字常量区的内容是不可以改变的
   printf("%s\n",p);
   printf("%d\n",sizeof(p));//4
   printf("%d\n", sizeof("abcdef"));//7
   printf("%d\n", strlen(p));//6
   printf("%d\n", strlen("abcdef"));//6
   *p = 'm';//err p指向的是文字常量区,文字常量区的内容是不能改变的
   printf("%s\n",p);
   system("pause");
   return 0;
}

5.3 字符指针作为形参

//字符串已经有了\0的标志,不需要传长度,只需要两个字符串作为参数
char * my_strcat(char * src, char *dst)
{
   int n = strlen(src);
   int i = 0;
   while (*(dst + i) !=  0)
   {
       *(src+n+i) =   *(dst + i);
       //src[n+i] = dst[i] ;
       i++;
   }
   *(src + n + i) = 0;
   return src;
}
int main()
{
   char str1[128] = "hello";//hello123456\0
   char str2[128] = "123456";
   my_strcat(str1,str2);
   printf("%s\n",my_strcat(str1, str2));
   system("pause");
   return 0;
}

tips:字符串已经有了\0的标志,不需要传长度

5.4 const修饰的指针变量

int main()
{
    char  buf[] = "hello";
    char  str[] = "acbg";
    const char  *p = buf;//const修饰指针,不能通过指针修改指针所指向的空间内容
    //*p = 'b';  err  不能通过p指针修改那块空间的内容
    char  * const  k = buf;//指针变量k初始化之后不能改变k指针变量本身的指向
//      k = "world"; err 
//      k = str; err
    system("pause");
    return 0;
}

5.5 字符指针数组

//字符指针数组
//是一个数组,每一个元素是字符指针
int main()
{
   /*char *p1 = "heihei";
   char *p2 = "haha";
   char *p3 = "xixi";*/
   //char *num[3] = { p1,p2,p3};
   char *num[3]={ "heihei" ,"haha","xixi"};
   //定义一个指针保存num数组首元素的地址   &num[0] == num
   char **p = num;
   for (int i = 0; i < 3; i++)
   {
   //  printf("%s\n",*(p+i));
       printf("%s\n", p[i]);//打印字符数组,需要首元素的起始地址
   }
   printf("%c\n",*(*(p+1)+3));// *(p[1]+3)   == p[1][3]
   //for (int i = 0; i < 3; i++)
   //{
   //      printf("%s\n",num[i]); 
   //}
   //printf("%c\n",*num[0]);//
   //printf("%c\n", *(num[1] + 1));
   //printf("%c\n", *(num[2]+2));
   system("pause");
   return 0;
}

在这里插入图片描述
应用1:字符指针数组作为main函数的形参

int main(int argc, char *argv[]);
  • main函数是操作系统调用的,第一个参数标明argc数组的成员数量,argv数组的每个成员都是char *类型
  • argv是命令行参数的字符串数组
  • argc代表命令行参数的数量,程序名字本身算一个参数
//.*.exe    hello   123456
//char *argv[] = { ".*.exe",    "hello"   "123456" };
int main(int  argc,char *argv[])
{
    /*printf("%d\n",argc);
    printf("%s\n", argv[0]);
    printf("%s\n", argv[1]);
    printf("%s\n", argv[2]);
    printf("%s\n", argv[3]);*/
    for (int i = 0; i < argc; i++)
    {
        printf("%s\n", argv[i]);//字符数组内元素的首地址
    }
    system("pause");
    return 0;
}

5.6 字符串处理函数

字符串函数(即:str开头的函数)的头文件都为#include <string.h>

strcpy()

strcpy(str1,str2);//将str2的字符拷贝至str1数组中,注意,str2遇到\0结束,会将\0拷贝至str1

int main()
{
    char str1[128] = "heiheihaha";
    char str2[128] = "world";
    strcpy( str1 ,  str2);
    printf("%s\n",str1);

    system("pause");
    return 0;
}
strncpy()

strncpy(str1,str2,n);//将str2中的前n个字符拷贝至str1中,如果拷贝时不足n个,遇到\0拷贝结束

int main()
{
    char  str1[1024] = "";//wo\0\0\0      wo\0rl
    char str2[128] = "wo\0rldhello";
    //strcpy( str1 ,  str2);
    strncpy(str1,str2,5);
//      printf("%s\n",str1);
    for (int i = 0; i < 5; i++)
    {
           printf("%d ",str1[i]);
    }
    system("pause");
    return 0;
}
strcat()
strncat()

strcat(str1,str2)//将str2字符数组中的字符连接到str1字符数组中,遇到\0结束
strncat(str1,str2,n)//将str2字符数组中的n个字符连接到str1字符数组中,遇到\0结束

int main()
{
   char str1[1024] = "123456";//wo\0\0\0      wo\0rl
   char str2[128] = "worldhello";
   //strcat(str1,str2);//将str2的字符串拷贝到str1字符串的后面
   strncat(str1, str2,5);
   printf("%s\n",str1);
   system("pause");
   return 0;
}
strcmp()
strncmp()

注意: 比较时遇到\0结束比较

int main()
{
    char  str1[] = "a\0bcdef";
    char str2[] = "a\0cdrrr";
    //str1数组中和str2数组拿出一个元素进行比较,相等继续往后比较
    //比较的是字符的ascii值
    //如果str1> str2  返回值等于1
    //如果str1==  str2  返回值等于0
    //如果str1 <str2  返回值等于 - 1
    //printf("%d\n",strcmp(str1,str2));
    printf("%d\n", strncmp(str1, str2,3));
    system("pause");
    return 0;
}
sprintf()

组包函数
int len = sprintf(buf,“格式”,“数据”);//将数据安装格式组包,存放在数组buf中

中间有\0的字符串组成的包,我想知道这个包的长度,而不是字符串的长度(strlen),怎么求?
sprintf有返回值,返回的是组完包的有效长度
在这里插入图片描述

int main()
{
   int  year = 2018;
   int  month = 10;
   int day = 20;
   char buf[1024] = "";
   //printf("year=%d month=%d day=%d \n",year,month,day);
   int len = sprintf(buf,"year=%d %cmonth=%d day=%d \n",year, 0,month, day);
   //printf("%d\n",strlen(buf));
   printf("len=%d\n",len);
   printf("buf=[%s]",buf);
   system("pause");
   return 0;
}
sscanf()

拆包函数
sscanf(buf,“格式”,数据);//将buf的内容格式化输出到数据

int main()
{
   //%d    0-9的字符
   int  year =0 ;
   int  month = 0;
   int day = 0;
   char  buf[1024] = "beijing:2018:t:10:20";
   //scanf("%d:%d:%d",&year,&month,&day);//从键盘按照相应的格式获取数据
   //格式按照别人的格式,我要什么数据就按那个数据的格式提取
   sscanf(buf, "beijing:%d:t:%d:%d", &year, &month, &day);//从buf中按照`相应的格式获取数据
   printf("%d %d %d\n",year,month,day);
   system("pause");
   return 0;
}
strchr()

strchr(buf,ch)//在buf字符数组中查找字符ch出现的位置,如果成功返回此字符出现位置的地址,如果没有找到,返回NULL

char *my_strchr(char *p, char ch)
{
    int i = 0;
    while (p[i] != 0)
    {
           if (p[i] == ch)
               return &p[i];
           i++;
    }
    if (p[i] == 0)
           return NULL;
}
int main()
{
    char  str[] = "xixihellogworld";
    char *p = strchr(str,'g');
    //char  *p =my_strchr(str,'g');
    printf("%s\n",p);
    system("pause");
    return 0;
}
strstr()

strstr(str1,str2)//在str1字符数组中查找str2字符串出现的位置,并且返回这个位置的地址

char *my_strstr(char *str1, char *str2)
{
    int i = 0;
    while (str1[i] != 0)
    {
           if (str1[i] == str2[0])
           {
               if (0 == strncmp(str1 + i, str2, strlen(str2)))
                  return str1 + i;
           }
           i++;
    
    }
    if (str1[i] == 0)
           return NULL;
}
int main()
{
    char str1[] = "helloaabcfhaffjhafafha";
    char str2[] = "abc";
    //在str1中查找str2字符出现的位置
    //先找a字符,如果找到了a字符,在比较
    char *p = strstr(str1,str2);
    printf("%s\n",p);
    system("pause");
    return 0;
}
strtok()

来将字符串分割成一个个片段。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时, 则会将该字符改为\0 字符,当连续出现多个时只替换第一个为\0。

int main()
{
   char str[] = "15080015225#bangquan#82263#123456";
   //第一次切
   //char *p1 = strtok(str,"#");//在str1中将#切割,返回切割前面的字符串
   //printf("%s\n",p1);
   
   //第二次注意不能再写str,不然还是返回上一次前面切割的一个字符串
   //第二次切割要从 \0 ——>NULL 后面开始切
   //char *p2 = strtok(NULL,"#");
   //printf("%s\n",p2);
   
   //第三次切也是从NULL,会自动记录切的位置,往后切
   //char *p3 = strtok(NULL, "#");
   //printf("%s\n", p3);

   char *p[10] = {NULL};//初始化指针数组元素全部为NULL
   int i = 0;
   do {
   		//第一次切和后面的切不同
        if(i == 0)
            p[i] = strtok(str, "#");
        //后面切
        else
            p[i] = strtok(NULL, "#");
   } while ( p[i++] != NULL);//如果strtok的返回值等于NULL,代表切割完毕

	//输出指针字符数组
   int j = 0;
   while (p[j] != NULL)
   {
       printf("%s\n",p[j++]);
   }
   system("pause");
   return 0;
}

tips:

如果遇到字符串为char str[] = "15080015225$bangquan#82263$123456";
要求:遇到$或者#都要切割
那么写为strtok(NULL, "#$");
"#$"代表遇到#或者$就切割

总结:

  • 在第一次调用时:strtok()必需给予参数s字符串
  • 往后的调用则将参数s设置成NULL,每次调用成功则返回指向被分割出片段的指针
char a[100] = "adc*fvcv*ebcy*hghbdfg*casdert";
char *s = strtok(a, "*");//将"*"分割的子串取出
while (s != NULL)
{
	printf("%s\n", s);
	s = strtok(NULL, "*");
}
atoi()

atoi()会扫描字符串,跳过前面的空格字符,直到遇到数字或正负号才开始做转换,而遇到非数字或字符串结束符(’\0’)才结束转换,并将结果返回返回值。
atoi : 将字符串转整数
atof: 将字符串转float类型的数据
atol: 将一个字符串转化为long类型

char str1[] = "-10";
int num1 = atoi(str1);
printf("num1 = %d\n", num1); //-10

char str2[] = "0.123";
double num2 = atof(str2);
printf("num2 = %lf\n", num2);

6 指针小结

在这里插入图片描述

7 字符串常见应用

7.1 求字符串中substr出现的个数

7.2 两头堵模型

7.3 字符串反转模型(逆置)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值