以上两种定义的方法是等同的。
#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;
}
#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。
int a[10],b[2+4*2];//[]中是常量,或者常量表达式
int* p[10];//数组元素类型为int*,即指向整型的指针变量
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] ;
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];
int a[5]={0,1,2,3+4,5+6};//{}中可以是常量、变量、表达式
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},是错误的
int a[]={1,2,3,4,5};//根据已有元素个数,默认a的长度为5
注意:不给出元素个数时,必须在定义时进行初始化,下面的是错误的
int a[];
a[]={1,2,3,4,5};
此时只能单个元素单个元素进行初始化,可以用循环
int a[10],i=0;
for(i=0;i<10;i++)
{
a[i]=i;
}
切记,定义后没有初始化,在后面初始化时错误的。
int a[5];
a[5]={1,2,3,4,5};
????????????????数组名[下表表达式]
#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;
}
#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;
}
运行结果:
#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;
}
数组指针,是一个指针,这个指针指向数组。
int a[5]={1,2,3,4,5};
int (*p)[5]=a;//优先级:()>[]>* ,所以p是一个指针;又有[],所以是指向数组的指针,数组中有5个元素
指针数组,是一个数组,数组元素的类型为指针。
int a,b,c;
int *p[3]={&a,&b,&c};//首先[3],p是一个数组,数组的元素是指针,指针指向int
只要记住,谁在后面就是谁(数组指针,指针在后,那就是指针),优先级:()>[]>*
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];
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}}};
进行全部初始化时,由于数组元素是线性存储的,因此也可以只用一对花括号。
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}};
对应各维列表的花括号“{}”不能省略,但花括号“{}”内其他维度或值可以省略,省略的值自动取0或NULL或'\0'。
int a[3][4]={{1},{5}};
上面代码等价于
#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;
}
二维数组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;
}
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'
字符串是用双引号括起来的若干字符,字符串在内存中连续存放,每个字符以ASCII吗形式占一个字节,并在最后添加字符‘\0’作为字符串结束标志,也就是说字符串的实际占用字节数为字符串长度+1。在C语言中,没有字符串数据类型,但是可以定义一位字符数组存放字符串,因此字符数组长度至少大于等于字符串长度+1。
char str[12]={'C',' ','p','r','o','g','r','a','m','\0'};
char str[12]={"C program"};
char str[12]="C program";
上面的存储形式如下:
下面的数组都会自动计算长度,并且不要忘记'\0'
char str[]={'C',' ','p','r','o','g','r','a','m','\0'};自动计算长度
char str[]={"C program"};
char str[]="C program";
存储形式如下:
上面都是用数组名str(数组首地址/指针变量)定义,也可以定义一个指向字符的指针变量,并初始化(一定要初始化,如何到后面再初始化有可能会使内存发崩溃)。
char *p="C program";
指针p指向了一个字符串常量" C program",它是在代码编译时分配的。这意味着该字符串常量在程序的整个执行期间都会存在,因此不需要手动为指针p分配内存空间。但是由于字符串常量是只读的,不能修改它们的内容。如果尝试修改指针p指向的字符串常量,将会导致不确定的行为。如果想要修改字符串的内容,应该将字符串存储在一个字符数组中,而不是使用指向字符串常量的指针
记住:用指针定义的不能修改,用数组定义的可以修改
#include<stdio.h>
int main()
{
char str[20];
scanf("%s",str);
puts(str);
return 0;
}
结果如下:
因为scanf函数输入字符时,遇到空格‘ ’认为输入结束,自动加入字符串结束标志'\0'。
#include<stdio.h>
int main()
{
char str[20];
gets(str);
puts(str);
return 0;
}
通过gets函数可以保留空格,并自动加入结束标志。
char str[30];
strcpy(str,"I love you.");
strcpy在头文件string.h中。
#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来对字符数组进行输出。
? ? 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.
? ? ? ? char* gets(字符数组名/指向字符的指针变量名)
返回“字符数组名或指向字符的指针变量”的值。当字符串有空格时,仍保留空格。
? ? ? ? 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头文件里面
? ? ? ? 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头文件中
????????int strcmp(p1(字符串/字符数组名/指针),p2(字符串/字符数组名/指针))
逐个比较两个字符串中对应字符ASCII码值的大小,直到对应的ASCII不相等,或者都是字符串结束标志'\0'为止。
strcmp("abc","abc");//返回0
strcmp("abc","ab");//返回1
strcmp("ab","abc");//返回-1
注意:strcmp包含在string.h头文件中
注意:以上三个函数的第二个参数都可以是字符串,而第一个参数不能是字符串(strcmp除外)
????????int strlen(字符串/数组名/指针)
返回字符串长度(不包含'\0'),如strlen("ab");返回2。
函数包含在string.h中