C语言基础复习(四)
1.指针
1.1指针变量的定义
- int? ?*pi1,? ?*p12,? ?*pi3;
- 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}};
上面代码等价于
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中
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!