C语言学习记录(六)

C语言学习记录(六)

一、知识要点(指针)

一、指针和指针变量

1、指针的概念

  • 内储存器:是用来存放程序和数据的装置,基本职能是正确存放和读取一个数据。他由一系列内存单元构成,而内存单元的编号叫做内存地址
  • 内存地址是不变的,但是内存单元里的数据可以变化。内存地址通常称为指针。通过指针可以访问内存单元中的数据。
  • 用来存放指针(某个内存地址)的变量叫做指针变量。用指针变量p来存放整形变量i的指针可以说p是指向变量i的指针。
  • 通过变量名本身去访问地址叫做直接寻址;通过访问指针变量来获得数据地址称为间接寻址
  • 指针变量中可以更换指针。数组和函数的数据是连续存放在地址中的,将数据的首地址和函数的入口地址存放在指针变量中,就可以直接访问全部数据。

2、指针变量的定义

  • 定义指针变量的语法格式为:类型名 *标识符;比如int *p。其中*表示标识符为一个指针变量。p是一个指针变量,他究竟指向那个整形变量,需要赋予p地址来决定。
  • 所有类型的指针变量都占用四个字节;
  • 一个指针变量的类型被定义后,就只能指向由定义限定的同一类型变量了。

3、指针运算及指针变量的引用

  • &运算符

    • &是单目运算符,结合性为右结合性。它的功能是取出操作对象在内存中的地址。&只能用于变量。
    • 例如int a;scanf("%d",&a);在这里就是取出整形变量a的地址。
  • *运算符

    • 这也是单目运算符,他的作用是在定义指针变量是做表明作用,在非定义状态下为访问操作对象所指的变量。

    • 例如int a = 20; int *p; p = &a;

    • #include<stdio.h>
      int main()
      {
      	int a = 20;
      	int* pa;
      	pa = &a;
      	printf("a = %d\n", a);
      	printf("*pa = %d\n", *pa);
      	printf("&a = %d\n", &a);
      	printf("pa = %d\n", pa);
      	printf("%d,%d\n", pa == &a, *pa == a);
      	return 0;
      }
      执行结果为:
      a = 20
      *pa = 20
      &a = 242219844
      pa = 242219844
      1,1
      

4、指针变量的赋值

  • 指针变量在使用之前不仅要先定义,而且必须赋予具体的值。指针变量的赋值只能赋予地址,不然将引起错误。

  • 常用的指针赋值运算

    • 指针变量的初始化int a;int*pa=&a;在定义指针变量pa的同时将变量a的地址作为初值。

    • 不允许把一个数赋给指针变量int*p;p=1000是错误的。

    • 把一个指针变量的值赋予指向相同变量的另一个指针变量。如int a,*pa=&a,*pd; pb=pa;即把a的地址赋予指针变量pb。

    • 把数组的首地址赋给指针变量:如int a[5],*pa;pa = a;或者int a[5],*pa;pa = &a[0];数组名表示数组的首地址,数组的第一个元素也是数组的首地址,即a和a[0]的值是相同的。

    • 、把字符串的首地址赋给指针变量:例如char*pc;pc = "C Language";

    • #include<stdio.h>//比较三个数的大小
      int main()
      {
      	int a, b, c, * pmax, * pmin;
      	printf("输入三个整数:");
      	scanf("%d%d%d", &a, &b, &c);
      	if (a > b)
      	{
      		pmax = &a;
      		pmin = &b;
      	}
      	else
      	{
      		pmax = &b;
      		pmin = &a;
      	}
      	if (c > *pmax)
      		pmax = &c;
      	if (c < *pmin)
      		pmin = &c;
      	printf("max = %d\nmin = %d\n", *pmax, *pmin);
      	return 0;
      }//不用交换a,b,c的值就可以比大小。
      

二、数组与指针

1、指向一维数组的指针

  • 一个数组是连续存放在一大块内存中的。每个数组元素按其类型占用不同数量的内存单元。一个指针变量既可以指向整个数组,也可以指向某个数组元素

  • 如果要使指针变量指向数组,可把数组名或者数组第一个元素的地址赋予它;如果要使指针变量指向一个数组元素,可把i元素的地址或者数组名加i赋予它。数组的首地址称为数组的指针,指向数组的指针变量称为数组指针变量

  • 数组的指针变量说明的语法格式为:类型名*标识符,现在访问数组不仅可以用下标法,还可以采用*p或*(pa+i)的形式。

  • #include<stdio.h>//使用不同方法访问数组a
    #include<math.h>
    
    int main()					
    {
    	int a[10], i;
    	for (i = 0;i < 10;i++)
    	{
    		a[i] = 2 * (i + 1);
    	}
    	int* p;
    	p = a;									//也可以写成p=&a[0]
    	
    	for (i = 0;i < 10;i++)
    		printf("%d ", a[i]);
    	printf("\n");
    
    	for (i = 0;i < 10;i++)
    		printf("%d ", p[i]);
    	printf("\n");
    	for (i = 0;i < 10;i++)
    		printf("%d ", *(a + i));
    	printf("\n");
    	for (i = 0;i < 10;i++)
    		printf("%d ", *(p + i));
    	return 0;
    }
    //由此可见,a[i]、p[i]、*(a+i)、*(p+i)是等效的
    

2、指针变量的运算

  • 加减运算和增量运算

    • p+n;p-n 指针变量加或减一个整数n是使指针向前或者向后移动n个位置,来指向另一数组元素p = &a[0]; p = p+3指的是把p的值向后移三个位置,就是&a[3]。

    • 指针变量和地址值的加减不一样,指针加减是移动到数组的某个位置,根据数组类型的不同,移动的地址数不同,而地址的加减与数组类型数据无关。

    • 指针元素的加减运算只对数组有效,其他屁用没有。

    • #include<stdio.h>//
      #include<math.h>
      
      int main()					
      {
      	int a[5], i, * pa;
      	pa = a;
      
      	for (i = 0;i < 5;i++)
      	{
      		*pa = i;					//把i的值赋给pa所指的数组元素
      		pa++;						//pa指向下一个元素
      	}
      
      	pa = a;							//再次把数组a赋给pa
      	for (i = 0;i < 5;i++)
      		printf("%d", *pa++);			
      
      	return 0;
      }
      
    • *(p++)指的是先取p的地址再自增一;*(++p)是p先自增一再取地址;(*p)++指的是先取地址,然后把p中数组元素的值加一,p本身不变; ++(*p)表示先把p中数组元素加一,但是p本身不变。

    • 通过指针访问数组元素效率高,因为系统访问a[i]时必须先计算a + i*d,而指针直接*p++。

    • 数组名是常量,不能赋值和自增运算。

  • 指针变量的相减运算

    • 两指针变量相减所得结果是两个指针所指的两个数组元素相差的的元素个数。p1-p2>0说明p1的地址比p2高。
    • 只有指向同一数组的两变量指针相减才有意义,不然屁用没有。
  • 指针变量的关系运算

    • p1 == p2表示p1和p2指向同一数组元素;

    • p1>p2表示p1处于高位置。

    • p1<p2表示p2处于高位置。

    • #include<stdio.h>					//两指针变量的比较
      #include<math.h>
      
      int main()
      {
      	int a[5] = { 5,20,8,6,13 };
      	int* p1, * p2, * p3;
      
      	p1 = &a[1], p2 = &a[3];
      
      	if (p1 > p2)
      		p3 = p1;
      	else
      		p3 = p2;
      
      	printf("%d\n", *p3);
      
      	p1 = p1 + 3, p2 = p2 - 3;
      
      	if (p1 > p2)
      		p3 = p1;
      	else
      		p3 = p2;
      
      	printf("%d\n", *p3);
      	return 0;
      }
      
    • 另外,指针变量还可以和0比较,如果p == 0,那么表示p是空指针,不指向任何变量。

3、指向二维数组的指针

  • 二维数组的地址

    • 设一个二维数组a[3][4],其首地址为1000。我们可以把二维数组a理解为是由a[0]a[1]a[2]组成的一维数组,而每个元素a[i]又是由四个四个元素组成的一维数组。

    • a是二维数组名,代表二维数组第一行的首地址,也就是1000。a[0]是第一行一维数组的数组名和首地址,其值也是1000。&a[0][0]是二维数组a的第1行第一列元素地址,其值同样也是1000。

    • a + 1是二维数组第二行的首地址,值为1016;a[1]和&a[1][0]与前面一样也都是1016。

    • 由此可以得出a + i、a[1]、*(a + i)、&a[1][0]的值都是相同的。但是,a + i,&a[i]表示第i行首地址,指向行;a[i],*(a+i),&a[i][0]指向列。

    • #include<stdio.h>					//确定数组每个成分的大小
      #include<math.h>
      
      int main()
      {
      	int a[3][4] = { {0,1,2,3},{4,5,6,7},{8,9,10,11} };
      
      	printf("The size of a = %u\n", sizeof(a));
      	printf("The size of a[0] = %u\n", sizeof(a[0]));
      	printf("The size of a[0][0] = %u\n", sizeof(a[0][0]));
      	return 0;
      }//由此可见,a代表整个数组,a[0]代表第一行,a[0][0]代表单个元素
      
    • #include<stdio.h>					//通过地址访问二维数组的元素
      #include<math.h>
      
      int main()
      {
      	int a[3][4] = { {0,1,2,3},{4,5,6,7},{8,9,3,6} };
      	int i, j;
      
      	for (i = 0;i < 3;i++)
      		for (j = 0;j < 3;j++)
      			printf("a[%d][%d] = %d		", i, j, *(a[i] + j));
      	printf("\n");
      	return 0;
      }
      
  • 指向二位数组元素的指针变量

    • 数组元素a[i][j]相对数组a起始地址的位移量是:i*4+j。其中i代表行数,j代表列数,4代表每行的元素。如果我们设立一个指针变量p,使它指向数组a的第一个元素a[0][0],即int*p = &a[0][0];那么就可以用*(p+(1*4+2))即*p+6来访问a[1][2]。

    • #include<stdio.h>					//通过指针变量访问二维数组元素
      #include<math.h>
      
      int main()
      {
      	int a[3][4] = { 1,3,5,7,9,11,13,15,17,19,21,23 };
      	int* p;
      
      	for (p = a[0];p < a[0] + 12;p++)
      	{
      		if ((p - a[0]) % 4 == 0)
      			printf("\n");				//访问一行后换行
      
      		printf("%4d", *p);
      	}
      
      	return 0;
      }
      
  • 指向行数组的指针变量

    • 也称为指向一维数组的指针变量,其定义的语法格式为:类型名(*指针变量名)[长度] 其中“长度”表示二维数组的列数,也就是一行的长度。

    • int (*p)[4]; p = a;//或p=&a[0],那么p+1指向一维数组a[1];p+i指向一维数组a[i]。*(p+i)+j指的是二维数组a[i][j]的地址,而*(*(p+i)+j)才是数组a[i][j]的值。

    • int main()
      {
      	int a[3][4] = { 1,3,5,7,9,11,13,15,17,19,21,23 };
      	int i, j, (*p)[4];
      	p = a;
      
      	for (i = 0;i < 3;i++)
      	{
      		for (j = 0;j < 4;j++)
      			printf("%4d", *(*p + j));
      
      		p++;
      		printf("\n");
      	}
      	return 0;
      }
      
    • 在使用指向一维数组的指针变量时,定义它的长度要和实际数组的列数相匹配。

    • 有以下形式的定义:int*p,(*pp)[4],设一个二维数组a,那么p只能指向数组元素的地址,即p+1指的是下一个元素;pp只能指向一维数组,p+1指的是下一行元素的首地址。

三、字符串与指针

1、字符串和字符串结束标志

  • 用一对双引号括起来的字符序列叫做字符串常量。如"sucaochac"、"a"都是字符串常量。
  • 字符串按序将各字符存放到一序列的内存空间,并且每个字符串后会附加储存一个空字符,也就是ASCII码为0的转义字符字符'\n'。这样在读取字符串时,就可以一个一个的读取,直到碰到'\0'字符为止。

2、字符数组

  • c语言中没有字符串变量,所以要用数组来存放字符串。将字符串中各个字符依次存放到数组各个元素中。同数值数组一样,字符串的数组名代表该数组的首地址

  • 一维数组的定义

    • 定义字符数组的语法格式:char 数组名[整形常量表达式],如:char a[10]
    • 因为每个字符串后面要跟一个\n,所以一个长度为n的一维数组最多只能存n-1个字符
  • 一维字符数组元素的初始化

    • 字符数组逐个元素赋初值:如有char ch[7] = {'H','e','l','l','o','\n'},当读取到第一个'\n'时,便不再往后读取。
    • 用字符串常量初始化字符数组:如char ch[6] = {"Hellow"};或者char ch[6] = "hellow";
  • 一维字符数组元素的引用

    #include<stdio.h>					//一维字符数组的引用
    
    int main()
    {
    	char a[] = { "Beijing2008" }, b[5] = { '\0' };//给数组b赋满终止符
    	int i;
    
    	for (i = 0;i < 4;i++)			//输入数组b的字符串
    		b[i] = a[i + 7];
    
    	for (i = 0;i < 11;i++)				//输出数组a中的字符串
    		printf("%c", a[i]);
    
    	printf("\n");
    
    	for (i = 0;i < 4;i++)			//输出数组b
    		printf("%c", b[i]);
    
    	printf("\n");
    	printf("%d\n", a[0]);			//输出a[0]的ASCII码
    
    	return 0;
    }
    
  • 一维数组的输入输出

    #include<stdio.h>					//字符的逐个输入输出
    
    int main()
    {
    	char c[12] = { '\0' };
    	int i;
    
    	for (i = 0;i < 12;i++)			//逐个输入字符
    		scanf("%c", &c[i]);
    
    	for (i = 0;i < 12;i++)			//逐个输出字符
    		printf("%c", c[i]);
    
    	printf("\n");
    
    	return 0;
    }
    
    • 输入过程中必须一次输入所有字符后按回车键。
    • 输入的字符中间可以包含空格符。
  • 整个字符串一次输入输出:

    char str[13];
    scanf("%s",str);
    printf("%s",str);
    
    • scanf函数自动把字符串的各个字符存放到str中的各个元素中,且在最后自动插入'\0'。
    • 用scanf函数输入字符串,会把空格、tap、回车当作结束符,这个要注意。
    • 用%s输出字符串时,输出项是字符数组名,而不是数组元素名。
  • 二维字符数组

    • 想要存放多个字符串,可以使用二维字符数组。其定义语法格式为:
      char 数组名[整形常量表达式][整形常量表达式];如: char a[3][10]。

    • 二维字符数组和二维数组相同,可以分成几个一维字符数组来存放字符串。

      #include<stdio.h>					//二维字符数组单个字符引用
      
      int main()
      {
      	char week[7][10] = { "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Satuiday" };
      	int i, j;
      
      	for (i = 0;i < 7;i++)				//依次输出各个字符串
      	{
      		for (j = 0;j < 10;j++)
      			printf("%c", week[i][j]);
      
      		printf("\n");
      	}
      
      	return 0;
      }
      
      #include<stdio.h>					//二维字符数组行的引用
      
      int main()
      {
      	char week[7][10] = { "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Satuiday" };
      	int i;
      
      	for (i = 0;i < 7;i++)				//按行输出字符串
      	{
      		printf("%s", week[i]);
      		printf("\n");
      	}
      
      	return 0;
      }
      
      • 由此可见,利用二维字符数组能够更方便地存储处理多个字符串。

3、指向字符串的指针变量

  • 指向字符串常量的指针变量

    • 只要获得存放字符的首地址,就可以访问和处理字符串中各个字符或整个字符串。所以就可以搞一个指针变量来指向字符了捏。
    • 字符指针初始化格式:char*指针变量名 = "字符串";其含义是:把字符串放到内存中,然后把字符串的首地址赋给字符指针变量。
    • #include <stdio.h>
      
      int main()                  
      {
          char*string;
          string = "This is a string";            //将字符串的首地址赋予指针
          
          printf("%s\n", string);
          string += 8;
      
          while (* string)                        //输出字符串,直到*string为零
          {
              putchar(string[0]);
              string++;
          }
      
          return 0;
      }
      
  • 指向字符数组的指针变量

    • 我们可以定义一个char类型的指针变量,然后将字符串数组地址赋予指针变量。

    • #include <stdio.h>
      
      int main()                  
      {
          char str[] = "This is a string.";
          char* string;                   //定义一个字符串数组和一个指针变量
          string = str;                   //将数组的首地址赋予指针变量
      
          printf("%s\n", str);            //输出数组str
          printf("%s\n", string);         //用指针变量间接输出字符串
          string += 8;
      
          while (* string)
          {
              putchar(string[0]);
              string++;
          }    
          
          return 0;
      }
      

4、字符数组与字符指针变量的对比

  • 字符数组由若干个元素组成,它存储了包括'\0'在内的字符串所有字符,可以通过各元素或数组名(常量)访问字符串。而字符串指针只存地址,不存放任何一个字符,可通过访问地址的方式来处理字符串。
  • char* str1; str1 = "I love Chine.";是可行的,因为str1是变量,可以把字符串首地址赋予它,但是char a[14]; a = "I love chine";是不行的,因为a是数组名,他是个常量,不能被赋值。
  • 定义一个字符数组,它的地址是确定的,而定义一个指针常量,虽然其本身的地址是固定的,但是其存放的地址是随机的,如果未对它赋予初始地址,可能产生严重后果

5、字符串处理函数

  • C语言的库函数中提供了一些关于操作字符串的标准函数,用户只要在程序的开头加上#include <stdio>和#include <string.h>就可以调用它们。

  • gets()函数

    • 调用格式:gets(数组名或字符串)

    • 函数功能与说明:从键盘输入字符串,gets会把读取到的字符存到数组名指向的数组中去,并自动在字符串末尾添加一个空字符'\n',如果输入的字符串长度超出,则会导致程序崩溃。在实际开发中不推荐使用,可以使用fgets()函数替代gets()函数

    • 示例

      #include <stdio.h>
      
      int main()                               
      {
          char str[100];
      
          printf("输入一段话:");
          gets(str);
          printf("你的输入:%s\n", str);
          
          return 0;
      }
      
  • puts()函数

    • 调用格式:puts(数组名或字符串)

    • 函数功能与说明:把数组中的字符串显示在屏幕上,输出时用'\n'代替'\0'

    • #include <stdio.h>
      
      int main()                               
      {
          char s1[20], s2[20] = "Hello\nWorld";
          
          gets(s1);
          puts(s1);
          puts(s2);
      
          return 0;
      }
      
  • strcpy()函数

    • 调用格式:strcpy(string1, string2);

    • 函数功能与说明:把string2复制到string1中去。string2是源字符串,它可以是字符数组名或字符指针,也可以是字符串常量,string1储存区首地址,它可以是数组名或者指针。要注意string1的储存空间要大于string2,并且string1如果是指针,则要赋值

    • #include <stdio.h>
      #include <string.h>
      
      int main() 
      {
          char a[10], b[100] = "你妈死了";
      
          strcpy(a, b);
          puts(a);
          puts(b);
      
          return 0;
      }
      
  • strcmp()函数

    • 调用格式:string(string1, syring2);

    • 函数功能与说明:从底层来看,这个函数是把两个字符串依次比较同一位置字符ASCII码大小,两个字符相同,则往后比较;若前者字符大与后者,则输出正数,反之输出负数。中文字符串需特殊处理。

    • #include <stdio.h>
      #include <string.h>
      
      int main() 
      {
          char str1[100];
          char str2[100];
      
          printf("输入字符串1:");
          gets(str1);
          printf("输入字符串2:");
          gets(str2);
      
          int res = strcmp(str1, str2);
      
          if(res < 0)
          {
              printf("str1比str2小");
      
          }
          else if(res > 0)
          {
              printf("str1比str2大");
          }
          else
          {
              printf("两者一样大");
          }
      
          return 0;
      }
      
  • strcat()函数

    • 调用格式:strcat(string1, string2);

    • 函数功能与说明:把string2连接到string1的末尾,注意要先保证string1已赋值,且有足够的储存空间。

      #include <stdio.h>
      #include <string.h>
      
      int main() 
      {
          char a[10] = "你tm就是";
          char b[] = "一个傻逼";
      
          strcat(a, b);
          printf("%s", a);
      
          return 0;
      }
      
  • strlen()函数

    • 调用格式:strlen(string);

    • 函数功能与说明:返回字符串中字符的个数(不包括字符串结束符'\0')。

    • #include <stdio.h>
      #include <string.h>
      
      int main() 
      {
          char a[] = "I am a handsome man";
          
          int b = strlen(a);
          printf("%d", b);
      
          return 0;
      }
      
  • strlwr()函数

    • 调用格式:strlwr(string);

    • 函数功能与说明:把字符串中大写字母转化为小写字母,其他字符不变。

    • #include <stdio.h>
      #include <string.h>
      
      int main() 
      {
          char a[] = "I AM A HANDSOME MAN";
          
          strlwr(a);
          printf("%s", a);
      
          return 0;
      }
      
  • strupr()函数

    • 调用格式:strupr(string);

    • 函数功能与说明:把字符串中小写字母转化为大写字母,其他字符不变。

    • #include <stdio.h>
      #include <string.h>
      
      int main() 
      {
          char a[] = "i am a handsome man";
          
          strupr(a);
          printf("%s", a);
      
          return 0;
      }
      

6、字符串应用举例

  • 上面的那些库函数也可以自己利用指针字符串编程实现,提高对指针的应用能力。

  • #include <stdio.h>              
    #include <string.h>
    
    int main()              //把s1的字符串赋给s2
    {
        char s1[] = "Hello,World";
        char s2[20];
        char* from = s1,* to = s2;
    
        while (* from)          //若数组s2的元素不为0,则把s2的值赋给s1
        {
            * to = * from;
            to++;
            from++;
        }
    
        * to = '\0';            //补0
        puts(s1);
        puts(s2);
        
        return 0;
    }
    
  • #include <stdio.h>              
    #include <string.h>
    
    int main()              //比较s1和s2的大小
    {
        char s1[80], s2[80];
        char* str1, * str2;
        int d;
    
        printf("请输入字符串1和字符串2:");
        gets(s1);
        gets(s2);
    
        str1 = s1;              //将s1、s2赋给两个指针
        str2 = s2;
    
        while (* str1 && * str2)        //比较每个字符大小
        {
            d = * str1 - * str2;
            if (d != 0)
            break;
            str1++;
            str2++;
        }
    
        printf("%d", d);
    
        return 0;
    }
    
  • #include <stdio.h>
    #include <string.h>
    
    int main()              //把s2接到s1后面
    {
        char s1[80], s2[80];    //定义两个字符串
        int i = 0, j = 0;       //定义两个计数器
    
        printf("输入字符串s1和s2:");     //提示用户输入两个字符串
        gets(s1);               //读取字符串s1
        gets(s2);               //读取字符串s2
    
        while (s1[i] != '\0')   //找到字符串s1的结尾位置
            i++;
    
        while (s2[j] != '\0')   //将字符串s2拼接到字符串s1的结尾
        {
            s1[i] = s2[j];      //将s2的第j个字符赋值给s1的第i个位置
            i++;                //将s1的位置指针指向下一个位置
            j++;                //将s2的位置指针指向下一个位置
        }
    
        s1[i] = '\0';           //在s1的结尾添加空字符
        puts(s1);               //输出拼接后的字符串
    
        return 0;               //程序结束
    }
    
  • #include <stdio.h>
    #include <string.h>
    
    int main()              ////该程序的功能是将一个字符串中的所有小写字母转换为大写字母,将一个字符串中的所有大写字母转换为小写字母,并输出转换后的两个字符串。
    {
        char s1[] = "BeiJing2008", s2[] = "BeiJing2008";    //定义两个字符串
        char* str1, * str2;     //定义两个指向字符的指针
        str1 = s1;              //将s1、s2赋给两个指针
        str2 = s2;
    
        while (* str1 != '\0')      //将s1中所有大写字母转换为小写字母
        {
            if (* str1 >= 'A' && * str1 <= 'Z')     //如果是大写字母
                * str1 += 32;                       //将其转换为小写字母
            str1++;                                 //将指针指向下一个字符
        }
    
        while (* str2 != '\0')      //将s2中所有小写字母转换为大写字母
        {
            if (* str2 >= 'a' && * str2 <= 'z')     //如果是小写字母
                * str2 -= 32;                       //将其转换为大写字母
            str2++;                                 //将指针指向下一个字符
        }
    
        puts(s1);           //输出转换后的字符串s1
        puts(s2);           //输出转换后的字符串s2
    
        return 0;           //程序结束
    }
    
  • #include <stdio.h>
    #include <string.h>
    
    int main()				//此程序的功能是从标准输入中读取一个字符串,然后去掉其中的空格,最后输出处理后的字符串。
    {
        char s[80], *p1, *p2;  // 声明变量 s,p1,p2
    
        printf("输入一个字符串:");
        gets(s);  // 从标准输入中读取一个字符串
    
        p1 = p2 = s;  // 初始化指针变量 p1,p2
    
        while (*p1)  // 遍历字符串 s
        {
            if (*p1 == ' ')  // 如果当前字符是空格,则跳过
                p1++;
            else
            {
                *p2 = *p1;  // 否则将当前字符拷贝到 p2 指向的位置,并移动 p1 和 p2 的指针位置
                p2++;
                p1++;
            }
        }
    
        *p2 = '\0';  // 在 p2 指向的位置添加字符串结束标志
    
        printf("%s", s);  // 输出处理后的字符串
    
        return 0;
    }
    
  • #include <stdio.h>
    #include <string.h>			//此程序的功能是从标准输入中读取一个长度不超过 8 的字符串,将其中的数字字符转换为整数,并输出转换后的结果
    
    int main()
    {
        char s[8], *p;  // 声明变量 s,p,n
        int n = 0;
    
        printf("请输入一个字符串:");
        gets(s);  // 从标准输入中读取一个字符串
    
        p = s;
    
        while (*p)  // 遍历字符串 s
        {
            n = n * 10 + (*p - 48);  // 将字符转换为数字,并累加到 n 中
            p++;
        }
    
        printf("%d", n);  // 输出转换后的结果
    
        return 0;
    }
    
  • #include <stdio.h>
    #include <string.h>
    
    int main()				//使字符串反向
    {
        char str[50], *p1, *p2, temp;  // 声明变量 str,p1,p2 和 temp
    
        printf("输入一个字符串:");
        gets(str);  // 从标准输入中读取一个字符串
    
        p1 = p2 = str;
    
        while (*p1)  // 找到字符串的最后一个字符
        {
            p1++;
        }
    
        p1--;
    
        while(p2 < p1)  // 将字符串反转
        {
            temp = *p2;  // 交换 p2 和 p1 指向的字符
            *p2 = *p1;
            p2++;
            *p1 = temp;
            p1--;
        }
    
        puts(str);  // 输出反转后的字符串
    
        return 0;
    }
    

四、指针数组和指向指针的指针

1、指针数组

  • 由多个相同类型的指针构成的数组叫做指针数组,即指针数组中每一个元素都是指针
    • 定义指针数组的语法格式为:类型名* 数组名[常量表达式];如int* pa[5];表示定义一个由五个指针变量构成的指针数组。而int(* pa)[5]指的是定义一个指向行的二维数组指针变量,不要把两个搞混了。
  • #include <stdio.h>
    #include <string.h>
    
    int main()
    { int a[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}}; // 二维数组a,包括3行4列 int* pa[3]; // 指针数组pa,包括3个元素,每个元素都是一个指向int类型的指针 int i, j;
    
    // 将二维数组的每一行的首地址赋值给指针数组的元素
    for (i = 0;i < 3;i++)
        pa[i] = a[i];
    
    // 遍历指针数组和二维数组,输出数组元素的值
    for (i = 0;i < 3;i++)
    {
        for (j = 0;j < 4;j++)
            printf("a[%d][%d] = %d  ", i, j, *(pa[i] + j)); // 使用指针访问二维数组的元素
        
        printf("\n");
    }
    
    return 0;
    }
    //将二维数组中的元素通过指针数组的方式逐一输出。在循环中,首先使用循环将二维数组中的每一行的首地址赋值给指针数组的对应元素,然后使用指针访问二维数组的元素并输出其值。
    
  • #include <stdio.h>
    #include <string.h>
    
    int main()
    { char* p[6] = {"FORTRAN","PASCAL","BASIC","COBOL","C","C++"}; // 字符串数组,包含6个元素,每个元素是一个指向char类型的指针 char* temp; // 用于在排序时暂存字符串指针的变量 int i, j, k;
    
    // 选择排序算法(无需改变数组元素位置)
    for (i = 0;i < 5;i++)
    {
        k = i; // 记录未排序元素中最小值的下标
        for (j = i + 1;j < 6;j++) // 找到未排序元素中最小值的下标
        {
            if (strcmp(p[k], p[j]) > 0) // 比较两个字符串的大小
                k = j;
        }
        if (k != i) // 如果最小值的下标不是当前元素的下标,则进行交换
            {
                temp = p[k];
                p[k] = p[i];
                p[i] = temp;
            }
    }
    
    // 输出排序结果
    for(i = 0;i < 6;i++)
        puts(p[i]); // 使用puts()函数输出字符串,每个字符串后面自动加上换行符
    
    return 0;
    }
    

​ 用指针数组出来字符串比用二维数组处理字符串更节约内存空间。

2、指向指针的指针变量

  • 我们可以定义一个指针变量int* pa使之指向变量a,那么pa可称为一级指针。再定义一个指针int* ppa使之指向pa,那么ppa可称为二级指针,以此类推,二级以上称为多级指针。

    • 定义二级指针的语法格式为:类型名 **指针变量名;二级指针变量就是储存一级指针变量的地址。
  • #include <stdio.h>
    #include <string.h>
    
    int main()
    { int a; // 声明一个整型变量a int *pa; // 声明一个指向整型变量的指针pa int **ppa; // 声明一个指向指针的指针ppa
    
    a = 100;  // 将100赋值给变量a
    pa = &a;  // 将变量a的地址赋值给指针pa
    ppa = &pa;  // 将指针pa的地址赋值给指针ppa
    
    printf("%d %d %d\n", a, pa, ppa);  // 依次输出变量a、指针pa和指针ppa的值
    printf("%d %d %d\n", a, *pa, **ppa);  // 依次输出变量a、指针pa和指针ppa所指向的值
    printf("%d %d %d", &a, pa, *ppa);  // 依次输出变量a的地址、指针pa所指向的值、指针ppa所指向的值所指向的值
    
    return 0;
    }
    

二、学习心得

感觉这一章比前面难好多啊,各种套娃层出不穷,先等我练一天题目熟练熟练

posted on 2023-03-19 21:38  嗷呜ニャー~  阅读(77)  评论(0编辑  收藏  举报