C语言基础复习(四)

发布时间:2024年01月02日

1.指针

1.1指针变量的定义

  1. int? ?*pi1,? ?*p12,? ?*pi3;
  2. int*? ?pi1,? ? pi2,? ? pi3;?

以上两种定义的方法是等同的。

1.2指针变量的访问

#include<stdio.h>
int main()
{
	int a=10,b,*p=&a;
	printf("a=%d,*p=%d\n",a,*p);
	*p=100;//间接赋值 
	p=&b;
	*p=a+200;//间接赋值 
	printf("b=%d,*p=%d\n",b,*p); 
    return 0;
}

1.3注意事项

  • 指针变量是变量,具有变量的特点,即可以取值和赋值
  • 星号“*”出现在不同的地方有不同的作用
  • 在定义变量中,int? *p;,此时“*”为指示符号,表明定义的变量为指针变量
  • 在指针类型定义中,int*? ?p;,此时“*”表明为指针类型

1.4指针变量的变化

  • 指针变化的基本单位是其所指向类型的存储单元数,如int型为4个字节,因而int型指针加减都以4为单位进行。
    #include<stdio.h>
    int main()
    {
    	int a=1,*pa=&a;
    	char c='a',*pc=&c;
    	printf("pa=%u,pa+1=%u\n",pa,pa+1);
    	printf("pc=%u,pc+1=%u\n",pc,pc+1);
        return 0;
    }

由上面可以看出,整型指针加1后,地址+4;char型指针+1后,地址+1。

2.一维数组

2.1一维数组定义

1.? ? ? ??数据类型符? ?数组名[常量/常量表达式]

	int a[10],b[2+4*2];//[]中是常量,或者常量表达式
	int* p[10];//数组元素类型为int*,即指向整型的指针变量

2.? ? ? ?数据类型符 [常量/常量表达式]? ? ?数组名

	int[10] a,b;//相当于int a[10],b[10] ;
	int[2+8] c,d;//相当于int c[2+8],d[2+8];也相当于 int c[10],d[10] ;

3.使用typedef

	typedef int IntVec[10];
	typedef int *PintVec[10];
	IntVec a,b,c;        //相当于int a[10],b[10],c[10]; 
	PintVec pa,pb,pc;    //相当于int *pa[10],*pb[10],*pc[10]; 

2.2一维数组初始化

2.2.1定义时进行初始化

2.2.1.1对所有元素赋值
    int a[5]={0,1,2,3+4,5+6};//{}中可以是常量、变量、表达式
2.2.1.2对部分元素赋值
	int a[5]={0,1,2};//a[3]、a[4]均为0 
	char c[5]={'a','b','c'};//c[3]、c[4]均为'\0'(数据值也是0) 

注意:部分初始化只能在前面初始化,不能在后面初始化,

如int a[5]={,,1,2,3},是错误的

2.2.1.3不给出数组元素个数
	int a[]={1,2,3,4,5};//根据已有元素个数,默认a的长度为5 

注意:不给出元素个数时,必须在定义时进行初始化,下面的是错误

	int a[];
	a[]={1,2,3,4,5};

2.2.2定义后进行初始化

此时只能单个元素单个元素进行初始化,可以用循环

	int a[10],i=0;
	for(i=0;i<10;i++)
	{
		a[i]=i;
	}

切记,定义后没有初始化,在后面初始化时错误的。

	int a[5];
	a[5]={1,2,3,4,5};

2.3一维数组访问

2.3.1直接访问

????????????????数组名[下表表达式]

#include<stdio.h>
int main()
{
	int a[5]={1,2,3,4,5};
	a[0]=90;
	printf("%d,%d",a[0],a[1]);
    return 0;
}

2.3.1直接访问之选择排序

#include<stdio.h>
int main()
{
	int a[10],i,j,t;
	for(i=0;i<10;i++) scanf("%d",&a[i]);
	for(i=0;i<10-1;i++)
	{
		for(j=i+1;j<10;j++)
		{
			if(a[j]<a[i])
			{
				t=a[i];
				a[i]=a[j];
				a[j]=t;
			} 
		}
	}
	for(i=0;i<10;i++)
	{
		printf("%d ",a[i]);
	}
    return 0;
}

运行结果:

2.3.2间接访问

  • 数组名是数组的首地址,arr==&arr[0]
  • arr+n,地址+数据类型所占空间*n。若arr为整型数组,则地址为arr+4*n,但是arr+n=&a[n]
  • arr[n]<==>*(&arr[0]+n)
  • &arr[4]-&arr[3]=&*(&arr[0]+4)-&*(&arr[0]+3)=(&arr[0]+4)-(&arr[0]+3)=1

2.3.2间接访问之选择排序

#include<stdio.h>
int main()
{
	int a[10],*i,*j,t;
	for(i=a;i<a+10;i++) scanf("%d",i);
	for(i=a;i<a+10-1;i++)
	{
		for(j=i+1;j<a+10;j++)
		{
			if(*j<*i)
			{
				t=*i;
				*i=*j;
				*j=t;
			} 
		}
	}
	for(i=a;i<a+10;i++)
	{
		printf("%d ",*i);
	}
    return 0;
}

2.4指针数组和数组指针

2.4.1数组指针

数组指针,是一个指针,这个指针指向数组。

	int a[5]={1,2,3,4,5};
	int (*p)[5]=a;//优先级:()>[]>*  ,所以p是一个指针;又有[],所以是指向数组的指针,数组中有5个元素 

2.4.2指针数组

指针数组,是一个数组,数组元素的类型为指针。

	int a,b,c;
	int *p[3]={&a,&b,&c};//首先[3],p是一个数组,数组的元素是指针,指针指向int

只要记住,谁在后面就是谁(数组指针,指针在后,那就是指针),优先级:()>[]>*

3.多维数组

3.1多维数组的定义

	int a[3][4];
	int[3][4] b;//等价于int b[3][4] ;
	int[4] c[3],d[5];//等价于int c[3][4],d[5][4]; 

3.2多维数组初始化

  • 初始化时每一维对应一堆花括号“{}”且对应初始化列表
	int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};//第一维有3个元素, 
	int b[2][3][2]={{{1,2},{3,4},{5,6}},{{7,8},{9,10},{11,12}}};

3.2.1全部初始化

进行全部初始化时,由于数组元素是线性存储的,因此也可以只用一对花括号。

int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};//等价于 int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

进行全部初始化时,还可以省略第一维的长度,但不能省略之后的维度。

	int a[][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};//第一维自动计算有3个元素
    int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12};//等价于 int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

3.2.2部分初始化

对应各维列表的花括号“{}”不能省略,但花括号“{}”内其他维度或值可以省略,省略的值自动取0或NULL或'\0'。

int a[3][4]={{1},{5}};

上面代码等价于\begin{bmatrix} 1& 0& 0& \\ 5& 0& 0& \\ 0& 0 & 0 & \end{bmatrix}

3.3多维数组直接访问

例题:在三维数组中查找极大值点

#include<stdio.h>
#define Mx 3
#define My 3
#define Mz 3
int main()
{
	int x,y,z,flag,v[Mx][My][Mz],t,j;
	for(x=0;x<Mx;x++)
	{
		for(y=0;y<My;y++)
		{
			for(z=0;z<Mz;z++)
			{
				scanf("%d",&v[x][y][z]);
			}
		}
	}
	for(x=0;x<Mx;x++)//判断每个点,是否为极值点,所以三重循环,对每个点进行判断 
	{
		for(y=0;y<My;y++)
		{
			for(z=0;z<Mz;z++)//第三重循环,精确到了某一个点 
			{
				flag=1;//通过这个标记,默认这个点(x,y,z)是极值点 
				for(t=0;t<Mx;t++)//先在X轴(维)方向判断 
				{
					if(t==x) continue ;
					if(v[t][y][z]>v[x][y][z])
					{
						flag=0;
						break;
					}
				}
				if(flag)//flag为非0,即flag为1,说明在X轴上最大 
				{
					for(t=0;t<My;t++)
					{
						if(t==y) continue;
						if(v[x][t][z]>v[x][y][z])
						{
							flag=0;
							break;
						}
					}
				}
				if(flag)//flag为1时,在X、Y轴上均为最大值,在Z轴上进行判断
				{
					for(t=0;t<Mz;t++)
					{
						if(t==z) continue;
						if(v[x][y][t]>v[x][y][z])
						{
							flag=0;
							break;
						}
					}
					
				} 
				if(flag)
				{
					printf("%d是极大值,坐标为(%d,%d,%d)\n",v[x][y][z],x,y,z);
				}
			}
		}
	}
    return 0;
}

3.4多维数组间接访问

二维数组a[3][4]可以理解为一维数组,一维数组的每个元素又是一个一维数组,具体可以看下图,

a+i=&a[i],*(a+i)=*&a[i]=a[i];

*(a+i)+j=a[i]+j=&a[i][j];

例题:已知5名学生的3们课程成绩,求每名学生的平均成绩、每门课程的平均成绩、以及总平均成绩。

#include<stdio.h>
int main()
{
	int i;
	float all_sc[5][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12},{13,14,15}};
	float s,average=0.0,*p,(*pr)[3];
	float av_st[5],av_sc[3],*ps=av_st,*pc=av_sc;
	p=*all_sc;
	while(p<*all_sc+5*3)
	{
		average==*p;
		p++;
	}
	average/=5*3;
	for(pr=all_sc;pr<all_sc+5;pr++)
	{
		for(s=0,p=*pr;p<*pr+3;p++)
		{
			s+=*p;
			*ps=s/3;
			ps++;
		}
		for(i=0;i<3;i++)
		{
			for(s=0,pr=all_sc;pr<all_sc+5;pr++)
			{
				s+=*(*pr+i);
			}
			*pc=s/5;
			pc++;
		}
	}
	for(i=0;i<5;i++) printf("student%d:%  .2f\n",i,av_st[i]);
	printf("math:%.2f\nC:%.2f\nFoxpro:%.2f\n",av_sc[0],av_sc[1],av_sc[2]);
	printf("Average:%.2f\n",average);
    return 0;
}

4.字符数组与字符串

4.1字符数组的定义和初始化

	char a[10]={'I',' ','a','m',' ','h','a','p','p','y'};
	char a[]={'I',' ','a','m',' ','h','a','p','p','y'};//长度可以省略,自动计算长度
	char a[10]={'a','b','c','d','e'};//后面5个元素自动初始化为'\0' 

4.2字符串与其结束标志

字符串是用双引号括起来的若干字符,字符串在内存中连续存放,每个字符以ASCII吗形式占一个字节,并在最后添加字符‘\0’作为字符串结束标志,也就是说字符串的实际占用字节数为字符串长度+1。在C语言中,没有字符串数据类型,但是可以定义一位字符数组存放字符串,因此字符数组长度至少大于等于字符串长度+1

4.3定义字符数组的几种形式

4.3.1带长度定义

	char str[12]={'C',' ','p','r','o','g','r','a','m','\0'};
	char str[12]={"C program"};
	char str[12]="C program";

上面的存储形式如下:

4.3.2不带长度定义

下面的数组都会自动计算长度,并且不要忘记'\0'

	char str[]={'C',' ','p','r','o','g','r','a','m','\0'};自动计算长度
	char str[]={"C program"};
	char str[]="C program";

存储形式如下:

4.3.3用指针变量定义

上面都是用数组名str(数组首地址/指针变量)定义,也可以定义一个指向字符的指针变量,并初始化(一定要初始化,如何到后面再初始化有可能会使内存发崩溃)。

	char *p="C program";

指针p指向了一个字符串常量" C program",它是在代码编译时分配的。这意味着该字符串常量在程序的整个执行期间都会存在,因此不需要手动为指针p分配内存空间。但是由于字符串常量是只读的,不能修改它们的内容。如果尝试修改指针p指向的字符串常量,将会导致不确定的行为。如果想要修改字符串的内容,应该将字符串存储在一个字符数组中,而不是使用指向字符串常量的指针

记住:用指针定义的不能修改,用数组定义的可以修改

4.3.4通过函数赋值

  • scanf函数
#include<stdio.h>
int main()
{
	char str[20];
	scanf("%s",str);
	puts(str);
    return 0;
}

结果如下:

因为scanf函数输入字符时,遇到空格‘ ’认为输入结束,自动加入字符串结束标志'\0'。

  • gets函数
#include<stdio.h>
int main()
{
	char str[20];
	gets(str);
	puts(str);
    return 0;
}

通过gets函数可以保留空格,并自动加入结束标志。

  • strcpy函数
	char str[30];
	strcpy(str,"I love you.");

strcpy在头文件string.h中。

4.3.5字符串给数组赋初值

#include<stdio.h>
int main()
{
	char (*p)[7];
	char arr[][7]={{"HHHHHH"},{"GGGGGG"}};
	for(p=arr;p<arr+2;p++)
	{
		printf("%s\n",*p);
	}
    return 0;
}

注意:这里的arr相当于一行的指针,也相当于字符串的首地址,将其赋值给p(p是一个数组指针),通过P来对字符数组进行输出。


4.4字符串处理函数

4.4.1 puts函数

? ? int puts(字符串/字符数组名/指向字符的指针变量名)

返回值一般不用,返回字符串长度,输出字符串。

	char str[15]="I love you.";
	char *p=str;
	puts("I love you.");//参数为字符串常量,输出 I love you.
	puts(str);//参数为数组名               输出 I love you. 
	puts(p);//参数为指针变量               输出 I love you. 
	puts(p+2);//指针向后移动两位           输出 love you.

4.4.2 gets函数

? ? ? ? char* gets(字符数组名/指向字符的指针变量名)

返回“字符数组名或指向字符的指针变量”的值。当字符串有空格时,仍保留空格。

4.4.3 strcat函数

? ? ? ? char* strcat(p1(字符数组名/指针),p2(字符串/字符数组名/指针))

删去p1字符串的后面的结束标志,把p2连接到p1后面。返回p1。(p1指向的内容已经改变)

#include<stdio.h>
#include<string.h>
int main()
{
	char p1[50]="I love";
	char p2[10]=" you.";
	strcat(p1,p2);
	puts(p1);//输出I love you.
    return 0;
}

strcat包含在string.h头文件里面

4.4.4 strcpy函数

? ? ? ? char*?strcpy(p1(字符数组名/指针),p2(字符串/字符数组名/指针))

把p2指向内容复制到p1中(包括p2的结束标志‘\0’,无论有没有结束标志,复制时都在后面加一个,无论是否超出范围),返回p1,

#include<stdio.h>
#include<string.h>
int main()
{
	char a[20];
	char b[]="I love you.";
	char p1[20]="abcdefgh";
	char p2[]="hello";
	strcpy(a,b);
	puts(a);         //输出I love you. 
	printf("\n");
	strcpy(p1,p2);
	puts(p1);       //输出 hello('\0'隐含了)
    return 0;
}

运行结果如下:

第二个只输出了p2中的内容,这是因为复制p2到p1,也复制了p2的结束标志'\0',而puts是以'\0'为结束标志,因此只输出hello。

注意:strcpy包含在string.h头文件中

4.4.5 strcmp函数

????????int strcmp(p1(字符串/字符数组名/指针),p2(字符串/字符数组名/指针))

逐个比较两个字符串中对应字符ASCII码值的大小,直到对应的ASCII不相等,或者都是字符串结束标志'\0'为止。

  • p1==p2,返回0
  • p1>p2,返回1
  • p1<p2,返回-1

strcmp("abc","abc");//返回0
strcmp("abc","ab");//返回1
strcmp("ab","abc");//返回-1

注意:strcmp包含在string.h头文件中

注意:以上三个函数的第二个参数都可以是字符串,而第一个参数不能是字符串(strcmp除外

4.4.6 strlen函数

????????int strlen(字符串/数组名/指针)

返回字符串长度(不包含'\0'),如strlen("ab");返回2。

函数包含在string.h

文章来源:https://blog.csdn.net/2303_77275067/article/details/135307025
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。