函数传参
以数组作为函数参数时,参数中数组第一维不需要填写长度,如
void a(int a[])
{
a[1]=1;
a[2]=2;
}
但如果超过一维,如二维数组,则第二维开始就要写长度,如
void b(int c[][5])
{
c[0][0]=1;
}
注意:
数组作为参数时,在函数中对数组元素的修改就等同于是对原数组元素的修改
数组不能作为返回类型出现
指针
注意指针变量定义时的细节
int *a; int* a;//无区别
int* p1,p2;//注意这里只有p1为int*型,而p2为int型
int b;int *p3=&b;//指针变量初始化,但注意b的地址赋给p3而非*p3,因为int*才是一个数据类型
一种新颖的scanf输入数组的方法
for(int i=1;i<=n;i++)
scanf("%d",a+i);//等同于scanf("%d",&a[i]);
一种新的枚举数组元素的方法
for(int* p=a;p<=a+n-1;p++)
printf("%d ",*p);
指针的减法
#include<cstdio>
#include<iostream>
int main()
{
int a[10]={0,1,2,3,4,5,6,7,8,9};
int *p1=a+5;
int *p2=a+7;
printf("p1 = %d p2 = %d\n",p1,p2);
std::cout<<"p2-p1 = "<<p2-p1<<std::endl;
}
不难发现上面p1,p2的具体数值相差8(1个int占用4个byte,2*4=8byte)
而p2-p1却等于2(两个指针相减代表的是两个地址之间的距离,而距离以基地址为单位,a[7]和a[5]相差了2个int所以为2)
指针传参实现swap
#include<cstdio>
#include<iostream>
/*第一种swap方法*/
void swap(int *p1,int *p2)
{
int temp=*p1;
*p1=*p2;
*p2=temp;
}
int main()
{
int a=5,b=233;
std::cout<<"a = "<<a<<" b = "<<b;
printf("\n");
int *p1=&a,*p2=&b;
swap(p1,p2);
std::cout<<"a = "<<a<<" b = "<<b;
return 0;
}
注意一个问题,有可能会把temp也定义为int*变量,这样的话由于没有初始化指针变量那么就会随机存放一个地址容易出错,所以如果要使用int *temp;的话需要先初始化指针变量temp,即
/*第一种swap方法的变形*/
void swap(int *p1,int *p2)
{
int x;
int *temp=&x;
*temp=*p1;
*p1=*p2;
*p2=*temp;
}
注意之前的所有传参都是向函数中传入一个副本,并不能改变原变量本身(包括swap里的交换也是对传入的地址副本所指向的数据所做的修改而不能修改地址本身),于是为了不使用指针也能实现对原变量的修改就使用引用。
引用简单来说就是不产生副本,而是给原变量起一个别名,这样一来对引用变量的操作就是对原变量的操作了
/*第二种swap方法*/
#include<cstdio>
#include<iostream>
void swap(int &p1,int &p2)
{
int temp=p1;
p1=p2;
p2=temp;
}
int main()
{
int a=5,b=233;
std::cout<<"a = "<<a<<" b = "<<b;
printf("\n");
swap(a,b);
std::cout<<"a = "<<a<<" b = "<<b;
return 0;
}
注意和取地址符&区分
总结传指针参数和引用两种方法,可以实现第三种swap方法
/*第三种swap方法*/
#include<cstdio>
#include<iostream>
void swap(int* &p1,int* &p2)//注意*应该在&前面,因为数据类型int*是一个整体
{
int* temp=p1;//不能int temp=p1,数据类型不同
p1=p2;
p2=temp;
}
int main()
{
int a=5,b=233;
std::cout<<"a = "<<a<<" b = "<<b;
printf("\n");
int *p1=&a,*p2=&b;
swap(p1,p2);
std::cout<<"a = "<<*p1<<" b = "<<*p2;
/*注意这里容易写成cout<<a<<b,由于我们这里交换的是a和b的地址,a与b没有变化
(不同于第一种方法实际上还是交换的是值)因此不能输出a与b
可以理解成第一、二种方法是改变了a,b房间里的内容
而第三种方法改变的是a,b房间的地址,原本a的地址p1变成了b的地址*/
return 0;
}
结构体
结构体中可以定义除了自己本身以外的所有数据类型(可以定义自身类型的指针变量)
struct student
{
int age;
int index;
student* next;
}zcy,zfq,*zss;
访问结构体中元素的方法有两种
(1)"."操作
zcy.age;
zcy.index;
zcy.next;
(*zzs).age;
(*zzs).index;
(*zzs).next;
(2)"->"
由于对于指针变量(*变量名)不简洁美观,于是有下面这种表示(两种方法完全等价)
zzs->index;
zzs->age;
zzs->next;
结构体的初始化
(1)手动初始化,比较麻烦
(2)构造函数初始化
构造函数就是用来初始化结构体的一种函数,其特点有:
1.不需要写返回类型
2.函数名与结构体一致
3.一个普通定义的结构体内部会生成一个默认的构造函数(但不可见)
struct student
{
int age;
int index;
student* next;
student(){}
/*正是因为这个无需用户提供任何初始化参数的构造函数存在,
才可以直接定义student类型而无需初始化*/
}zcy,zfq,*zss;
使用构造函数初始化结构体的例子
struct student
{
int age;
int index;
student* next;
student(){}//默认的
student(int _age,int _index){age=_age;index=_index;}
/*也可以写成下面这个*/
student(int _age,int _index):age(_age),index(_index) {}
}zcy,zfq,*zss;
注意:构造函数可以写多个以适应各种情况,并且默认的无参数构造函数会被自己定义的覆盖掉一般都要手动加入一个默认的以实现不初始化就能定义结构体变量
struct student { int age; int index; student* next; student(){}//默认的 student(int _age,int _index):age(_age),index(_index) {} student(int _age):age(_age) {} }zcy,zfq,*zss;
cin、cout
cin如果想要读取一整行,则需要使用getline函数(可以读取空格、tab,换行结束),如下
char str[100];
cin.getline(str,100);
如果是string类容器,则需要
string str;
getline(cin,str);
cout可以控制输出的精度等特性但太麻烦了,还是主要用scanf、printf少用流输入输出(string用cin输入)