目录
-
標識符與關鍵字
標識符的第一個字符必須是字母或者下劃線
標識符中不應該含有除了字母,數字,下劃線之外的字符
標識符的長度一般不超過31個字符
-
註釋
/* 和 */擴起來進行註釋,在/* */之間的字符都被作爲註釋,適用於多行註釋
//從//到詞行末尾皆爲註釋,適用於單行註釋
-
變量
變量的聲明格式如下:
變量數據類型 變量名;
也可以使用如下格式聲明多個同類型的變量
變量數據類型 變量名1,變量名2,,,,變量名n;
*不同類型的變量不能在一個語句中聲明
變量類型1 變量名a,變量類型2 變量名b;
這樣的方式是錯的;
變量的初始化:
變量名=初始值;
也可以在聲明變量的時候進行初始化
變量類型 變量名 = 初始值;
*設置的初始值一定要符合變量的數據類型,例如:
int n=1.5;
是錯誤的,而
int i=1;
是正確的;
常用的數據類型:
- 整數型 int;
- 長整數型 long ;
- 短整數型 short;
- 無符號數型 unsigned int;
- 無符號的長整數與短整數 unsigned long;unsigned short;
- 實數型(浮點型) float;
- 實屬在C++中也可以包含一個含指數形式的數值; 如:1.5e3其中1.5是尾數部分,3是指數部分,表示數值爲1500;1.23e-2其中1.23是尾數部分,-2是指數部分,表示的數值是0.0123;
- 注意,字母e和E之前必須是有數字的,後面的指數部分必須是整數;
- 雙精度類型 double;
- 長雙精度long double;
- 字符型char;
- 無符號字符型unsigned char;
- 布爾型bool,布爾型是表示邏輯值的簡單類型,只有兩個值false和true前者序號爲0,後者序號爲1;
- 布爾型聲明時的初始化:bool no=false;
- 注意:在C++中,只要數值不等於0都表示1(包括負數),只有0才表示假;
- 程序中不會改變的常量const
- 常量的聲明格式:const 數據類型 變量名=文字常量;
- 聲明一實型常量時。如果實行常量沒有任何說明,則默認爲雙擊讀常量,如果表示但經讀實型常量則要在實型文字常量後加上F和f,如果要表示長雙精度實型常量則要在該實型文字後加上L或l;
- 除了聲明語句在程序中的其他地方不能在賦值;例如下面例子修改了常量的數值導致編譯錯誤;
#include <iostream> int main() { const float PI=3.1415926; PI=1; return 0; }
- 各種禁止的常量:
- 十進制爲正常輸入即可;
- 八進制在數字錢加上0;
- 十六進制在數字錢加上0x;
- 變量的引用:
- 聲明方式:數據類型 &引用名 變量名;
- 直接初始化:數據類型 &引用名=變量名;
- 一般情況下定義引用的時候必須初始化:
int i=10;
int & n=i; //直接初始化
- 綜合應用--計算園的面積
#include <iostream> using namespace std; int main() { const float PI=3.1415926F;//聲明並初始話一個常量PI; float r=0; //創建一個單精度的變量存放半徑值,並初始化爲0; float fAea=0;1 //創建一個單精度的變量存放園的面積,並始化爲0; cout<<"情輸入園的半徑值\n"<<endl; cin>>r; fAea=PI*r*r; cout<<"園的面積爲:"<<fAea<<endl; return 0; }
-
算數運算符
#include <iostream>
using namespace std;
int main()
{
int num1,num2,num3,num4,num5;//聲明五個變量;
num1=3+8;
num2=10-7;
num3=num1*num2;
num4=num3/5;
num5=num4%7;//取摸運算,又稱取於運算;
cout<<"num1="<<num1<<"\n";
cout<<"num2="<<num2<<"\n";
cout<<"num3="<<num3<<"\n";
cout<<"num4="<<num4<<"\n";
cout<<"num5="<<num5<<"\n";
return 0;
}
-
自增於自劍
-
a++,a--;其中a++與a--的區別在於a++中是先使用a的值在執行a=a+1;而++a是先執行a=a+1後在是引用a的值;
注意:自贈與自劍只能用於變量而不能呢個用於常量和表達式,如8++是不合法的,(a*c)++也是不合法的;
-
-
複合運算符
- 變量 運算符 = 表達式
- 例如:
a+=2;//等價與a=a+2;
a-=2;//等價與a=a-2;
-
位運算符
- 左移位運算實例:
在計算機中,7被表示爲0000 0000 0000 0111;#include <iostream> int main() { int n=7; int left_n=; left_n=n<<4; cout<<"left_n"<<left_n<<endl; return 0; }
左移4位後,變成0000 0000 0111 0000;空位用0填充;所以最後輸出爲112;
同理:右移運算符爲>>;- 注意:在右移位的時候,只有移位的變量是正數的時候,纔會用0作爲填充位,要是是負數的話,右移位的結果是無法預料的,左移沒有此限制,右移位一次相當於對當前數值每次除2;
- 位於運算符除了移位,還有按位與&,按位或 |,按位異或^;
- 左移位運算實例:
-
關係運算符
-
小於<,小於等於=,大於>,大於等於>=,等於==,不等於!=;
-
-
不像運算符的運算符
- new:
- delete:
- sizeof:
-
運算符的優先級以及結合性
#include <iostream> using namespace std; int main() { int i=0; float f=0; int m=5; int n=9; i=6*3+3%7-4/3; f=210+4.3e4+5.6/0.03; cout<<"i="<<i<<"\tf="<<f<<endl; i=n++ - --m; cout<<"i="<<i<<"\tm"<<m<<"\tn="<<n<<endl; return 0; }
-
不同變量類型之間的轉換
-
隱式轉換
一般是小的轉換爲大的;char->short->int->unsigned->long->unsigned int->float->double -
顯示轉換,其格式如下:
(數據類型)表達式
-
-
轉換實例
#include <iostream> using namespace std; int main() { short i=6; int n; float m=3.2f; double j; n=i; //隱式轉換 j=m; //隱式轉換 cout<<"n="<<n<<"\tj="<<j<<endl; j=4.5; m=(float)j; cout<<"m="<<m<<"\tn="<<n<<endl; return 0; }
-
語句
-
條件語句
- 格式:if(條件)語句;
例如:if(5>3)cout<<"真"<<endl; - 注意:作爲條件的表達式,不要使用賦值語句,因爲賦值表達式的結果永遠是正確的;
- 格式:if(條件)語句1else 語句2;
- 格式:if(條件)語句1
else if(條件2)語句2
else if(條件3)語句3
else 語句n;
- 格式:if(條件)語句;
-
邏輯運算符
- &&
- ||
- 實例
#include <iostream> using namespace std; int main() { int health=0; int number=0; int school=0; int suit=0,exce=0; cout<<"你是否是特長生[是1,否0]:"; cin>>suit; cout<<"\n"<<"你是否是報送生[是1,否0]"; cin>>exce; if(suit||exce) { cout<<"可以錄取"<<endl; } else { cout<<"請輸入學生成績:"; cin>>number; cout<<"情輸入學生狀態,[健康1,不健康2]"; cin>>health; cout<<"請輸入學生是否具有高中學歷[是1,否2]"; cin>>school; if(health&&school&&(number>500)) { cout<<"可以錄取"<<endl; } else { cout<<"不可以錄取"<<endl; } } }
-
受判斷的語句
-
表達式1?表達式2:表達式3;
-
-
循環
-
while
-
while(條件) 語句;
#include <iostream> using namespace std; int main() { int n=1,sum=0; while(n<100) { sum+=n; n+=2; } cout<<"sum="<<sum<<endl; }
-
-
當形循環do-while
-
do
語句
while
注意:do-while和while的區別在於do-while至少進行一次循環,而while可以不經型循環;#include <iostream> using namespace std; int main() { int n=1,sum=0; do { sum+=n; n+=2; } while(n<100); //判斷n是否小於100,循環結束; cout<<"sum="<<sum<<endl; }
-
-
循環語句for
- 格式:for(表達式1;表達式2;表達式3)語句
一般情況下,表達式1 用來個循環變量初始化,表達式2用來判斷循環結束的條件,表達式3用來作爲循環變量增加或減少的尋算;#include <iostream> using namespace std; int main() { int n,sum=0; for(n=1;n<100;) { sum+=n; n+=2; } cout<<"sum="<<sum<<endl; }
- 格式:for(表達式1;表達式2;表達式3)語句
-
選擇switch
- 格式:
switch(條件表達式)
{
case 常量表達式1:語句1;
case 常量表達式2:語句2;
case 常量表達式3:語句3;
case 常量表達式4:語句4;
default:語句n+1;
} - 實例
#include <iostream> using namespace std; int main() { char nGrade; cout<<"請輸入學生的等級:"<<endl; cin>>nGrade; switch (nGrade) { case 'A': cout<<"90分以上"<<endl; break; case 'B': cout<<"80到90"<<endl; break; default: cout<<"其他"<<endl; } }
- 格式:
-
循環的嵌套
-
退出與跳過
- 退出break:跳出當前循環;
- 跳過continue:跳過後面的語句,開始下一次循環;
-
-
函數
-
初步使用
#include <iostream> using namespace std; void printstar() { for(int i=0;i<50;i++) { cout<<"*"; } cout<<endl; } int main() { printstar(); cout<<"HelloWorld!"<<endl; printstar(); }
-
函數聲明
#include <iostream> using namespace std; void printstar(); int main() { printstar(); cout<<"HelloWorld!"<<endl; printstar(); } void printstar() { for(int i=0;i<50;i++) { cout<<"*"; } cout<<endl; }
-
函數的參數
-
注意:無參函數可以有返回值也可以沒有返還值;
在定義函數時,函數名後面的園括號()中的變量名稱被稱爲形式參數,而在調用函數時,括號中表達式的實際數值被稱爲實際參數;
#include <iostream> using namespace std; void min(int x,int y);//形式必須保持一致; int main() { int a=0,b=0; cout<<"請輸入兩個數字:"; cin>>a>>b; min(a,b); } void min(int x,int y) { if(x>y) { cout<<"x>y"<<endl; } else { cout<<"x<y"<<endl; } }
-
書記參數和形式參數的個數因該是一致的
-
函數的返回值
-
要獲得函數的返回值,被調函數中必須有return語句;
return 表達式;
不包含表達式的返回語句:return; -
如果表達式值的類型與函數的類型不相同時,將表達式的類型自動裝爲函數的類型,這種轉換是強制性的額;
例如:
int max(int x,int y);
char getchar();
float min(float a,float b); -
#include <iostream> using namespace std; int min(int x,int y); int main() { int a=0,b=0,c=0; cout<<"請輸入兩個數字:"; cin>>a>>b; c= min(a,b); cout<<"兩個數字的最小值爲:"<<c<<endl; } int min(int x,int y) { return (x<y?x:y); }
-
void類型的函數可以有無表達式return的返回語句,也可以沒有return語句
-
函數聲明和定義的時候可以給一個或多個參數指定默認值
例如:
int add(int x,int y=1);
int sum(int x,int y=12,int z=20);
上述對函數的聲明中,對函數最右面的一個或兩個參數指定默認值,但要注意,c++中,規定在指定了默認值的參數的右面,不能在出現愛呢沒有指定默認值的參數; -
當實際參數的數目不足的時候,編譯器會聲明或定義中的默認值來補足缺少的實際參數,如下:
int add(int x,int y=8)
那麼在調用這個函數的時候,只需要輸入一個參數就可以了:如下
int add(8)
等價爲
int add(10,8);
注意:給函數的參數指定默認值的時候,不僅可以使一個常量,也可以是任意有確定值的表達式;#include <iostream> using namespace std; void printnum(int x=2,int y=5,int z=10); //指定型慘的默認值 int main() { printnum(); printnum(100); printnum(100,10); printnum(100,10,25); cout<<"End!"; } void printnum(int x,int y,int z) { cout<<"x="<<x<<"y="<<y<<"z="<<z<<endl; }
-
參數的修飾符
-
例如:int add(const int x,int y);
對add的x型慘設置了const修飾副,表達式x在函數add中是不能被改變的,相當於常量;
-
-
函數的調用
#include <iostream> using namespace std; int add(int x,int y); int main() { //int t=10+add(10,30); int t=add(10,add(10,30)); cout<<"t="<<t<<endl; } int add(int x,int y) { return x+y; }
-
其實傳數值調用的實現機制就是將系統的實際參數賦值一個副本給型慘嗎在被調用的函數中,形參的值可以被改變,但只影響副本中的型慘值,而不影響主調函數中的實際參數值,所以傳遞數值調用的特點就是形參值的改變不影響實際參數值;例如:
#include <iostream> using namespace std; void swap(int x,int y) { int temp=x; x=y; y=temp; cout<<"x="<<x<<"y="<<y<<endl; } int main() { int i=10,n=20; swap(i,n); cout<<"i="<<i<<"n="<<n<<endl; }
-
函數的引用調用,使用引用調用作爲函數的方式,調用的實際參數只能是變量,將實際參數賦值給形參引用的時候,相當於在被調用的函數中給實參一個別名,如果引用形參的數值改變了,實質上的實參也被改變了;
#include <iostream> using namespace std; void swap(int &x,int &y) { int temp=x; x=y; y=temp; cout<<"x="<<x<<"y="<<y<<endl; } int main() { int i=10,n=20; swap(i,n); cout<<"i="<<i<<"n="<<n<<endl; }
-
函數的重載
-
參數類型上的重載函數
#include <iostream> using namespace std; int mult(int x,int y); float mult(float x,float y); int main() { int n=mult(10,10); float m= mult(15.5f,1.5f); cout<<"n="<<n<<endl; cout<<"m="<<m<<endl; } int mult(int x,int y) { return x*y; } float mult(float x,float y) { return x*y; }
-
參數個數不同的重在函數
#include<iostream> using namespace std; int max_1(int a,int b); int max_1(int a,int b,int c); int max_1(int a,int b,int c,int d); int main() { int num1=max_1(15,30,20); int num2=max_1(8,20,2,15); cout<<"num1="<<num1<<endl; cout<<"num2="<<num2<<endl; } int max_1(int a,int b) { return a>b?a:b; } int max_1(int a,int b,int c) { int t=max_1(a, b); return max_1(c,t); } int max_1(int a,int b,int c,int d) { int t= max_1(a, b); int n= max_1(c, d); return max_1(n, t); }
-
函数的嵌套使用
-
#include <iostream> using namespace std; void fun1(); void fun2(); int main() { cout<<"在主函数中"<<endl; fun1(); cout<<"返回主函数"<<endl; } void fun1() { cout<<"在fun1中"<<endl; fun2(); cout<<"返回fun1函数"<<endl; } void fun2() { cout<<"在fun2函数中"<<endl; }
-
内联和递归函数
-
内联函数:提高程序的执行效率;
增加目标代码空间占有率换取时间上的节省;
格式:
inline 函数名 (参数表; //内联函数声明
inline 函数名(参数表) //内联函数定义
#include <iostream> using namespace std; inline int intpower(int x); int main() { for(int n=1;n<=10;n++) { int m= intpower(n); cout<<n<<"的平方是:"<<m<<endl; } } inline int intpower(int x) { return x*x; }
代码第二行声明intpower是一个内联函数,从第11-14行定义了函数intpower胡函数体,代码第7行调用intpower,因为是内联函数所以会把它替换为如下形式:
int m=n*n;
-
递归函数:提高代码可读性,看起来简洁;
// 求最大公约数,算法为:操作数1对操作数2取余,如果为0,则操作数2为最大公约数,否则,操作数2对余数1继续取余,直至余数为0; #include <iostream> using namespace std; int gcdt(int x,int y); int main() { int n= gcdt(20,6); cout<<"最大公约数:"<<n<<endl; } int gcdt(int x,int y) { if(x%y==0) { return y; } return gcdt(y,x%y); }
//进行阶乘计算 #include <iostream> using namespace std; int factorial(int x); int main() { int n,m; cout<<"请输入进行阶乘的数值:"; cin>>n; m= factorial(n); cout<<"m="<<m<<endl; } int factorial(int x) { int t; if(x==0) { t=1; } else { t=x*factorial(x-1); } return t; }
-
-
-
-
-
系统函数的使用
<cstring>#include <iostream> #include <cstring> using namespace std; int main() { char str1[50],str2[50]; char str3[]="hello"; char str4[]="goodbye"; strcpy(str1,str3);//把str3复制到str1 cout<<"str3的长度:"<<strlen(str3)<<endl; cout<<"str1:"<<str1<<endl; strcpy(str2, strcpy(str1,str4)); cout<<"str2:"<<str2<<endl; strcat(str1,strcat(str2,str3)); //把后面的连接到前面字符的后面; cout<<str1<<endl; cout<<"字符串的链接:"<<strcat(str1,str2)<<endl; cout<<"str1:"<<str1<<"---"<<"str2:"<<str2<<endl; cout<<strcmp(str1,str2)<<endl;//比较大小,前面大于后面输出大于1,相等为0,反之输出小于1; cout<<strncmp(str1,str2,4)<<endl;//比较n个; int i; for(i=0;i<=49;i++) { str1[i]= '*'; } cout<<"str1:"<<str1<<endl; cout<<"str1:"<<strncat(str1,str2,4)<<endl;//连接n个; }
-
-
存储分类符
-
存储分类符:
- auto自动类
- register寄存器类
- static静态类
- extern外部类
-
自动变量
- auto int i;
- 自动变量的生存期为跳出函数体后者分成序,自动变量所占用胡空间就被系统释放了;
-
寄存器变量
- 定义时在前面加上关键字register
register int i;
- 定义时在前面加上关键字register
-
静态变量
- 内部静态变量;
#include <iostream> using namespace std; void func(); int main() { static int i=10;//声明为内部静态变量; func(); cout<<"在主函数内,i的值为:"<<i<<endl; func(); cout<<"在主函数内,i的值为:"<<i<<endl; } void func() { static int i=1;//声明i为内部静态变量; i+=3; cout<<"在func函数内,i的值为:"<<i<<endl; }
- 外部静态变量;
#include <iostream> using namespace std; static int i;//定义一个外部静态变量; void func(); int main() { cout<<"i="<<i<<endl; func(); cout<<"i="<<i<<endl; i+=10;//增加外部静态变量i的值; cout<<"i="<<i<<endl; } void func() { i+=4; }
外部变量又被称作全局变量,其在同一文件可以被函数内部和外部访问,生存周期为整个程序执行期间,定义一个外部变量胡方法是文件中的任意位置,只要不在函数体内直接定义一个变量即可;
- 静态变量生存期为整个程序执行期间;函数退出后占用空间不会被释放;
- 注意:外部变量的初始值和静态变量一样,int型为0,单精度为0,char为空,即null
- 外部变量在程序中的作用域和生存期;
#include <iostream> using namespace std; int i;//定义外部变量i; void func1();//声明函数func1; void func2();//声明函数func2; int main() { i=20;//改变外部变量i的值; cout<<"main():i="<<i<<endl; func1();//调用test1.cpp文件中的函数func1; cout<<"main():i="<<i<<endl; func2();//调用test2.cpp文件中的函数func2; cout<<"main():i="<<i<<endl; }
#include <iostream> using namespace std; extern int i;//声明外部变量i void func1() //func1函数的声明 { cout<<"func1():i="<<i<<endl; i=28; //改变外部变量的值; }
#include <iostream> using namespace std; extern int i;//声明外部变量i void func2() //func2函数的定义 { cout<<"func2():i="<<i<<endl; i=88; //改变外部变量i的值; }
- 内部静态变量;
-
内部函数和外部函数
- 内部函数是定义在其文件中可以被调用,而在同一个工程的其他文件中势不可以被调用的;定义内部函数用关键字static,格式如下:
static 数据类型 函数名(参数表)
{
函数体
} - 外部函数
extern 数据类型 函数名(参数表)
{
函数体;
}
其中,用extern关键字定义外部函数,不过在一半情况下在定义时可以省略;#include <iostream> using namespace std; int n=8;//定义外部变量 extern int func1(int x);//声明外部函数 int func2(int x);//声明外部函数,省略extern; int main() { for(int i=0;i<2;i++) { cout<<"func1:"<<func1(i)<<endl;//调用外部函数func1; cout<<"func2:"<<func2(i)<<endl;//调用外部函数func2; } }
static int n=10;//静态外部变量 int func1(int x)//定义外部函数,省略extern { return n+x;//使用外部静态变量n; }
extern int n;//声明外部变量 extern int func2(int x)//定义外部函数 { return n+x;//使用外部变量x; }
注意:外部变量就像全局变量,可以被声明很多次,并且只要被声明,就可以被程序中所有函数使用;
- 内部函数是定义在其文件中可以被调用,而在同一个工程的其他文件中势不可以被调用的;定义内部函数用关键字static,格式如下:
-
数组
-
数组的声明
-
格式
- 数据类型 数组名[大小];
-
声明时初始化
-
main() { int nArrary[4]={18,20,30,45}; ...... }
注意:花括号中要初始化胡元素数值个数必须是和数组声明时方括号[}中指定胡数组长度相符。元素之间要用逗号隔开;
-
如果要全部初始化为0;初始化方法如下:
int nArray[4]={0}; -
当然也可以忽略数组大小的说明,直接初始化数组,声明如下:
main()
{
int nArray[]={18,20,30,45};
}
注意:只有在数组立即初始化的时候才能这样声明;int -
int nArray[10]={1,2,3};
前三个元素初始化为1,2,3,剩下胡元素均默认赋值为0; -
数组元素的访问
数组名[元素序列号] -
示例
#include <iostream> using namespace std; int main() { int i=0; int f[20]={1,1}; for(i=2;i<20;i++) { f[i]=f[i-2]+f[i-1];//后项的结果等于前两项的和; } for(i=0;i<20;i++) { if(i%5==0) { cout<<endl; } cout<<f[i]<<" "; } }
- 数组传递给函数
#include <iostream> using namespace std; void disp(int nArray[],int len) { for (int i = 0; i < len; i++) { nArray[i]=0; } } int main() { int nArray[]={10,20,30,40};//声明并初始化数组nArray; int i=0; disp(nArray,4); for(i=0;i<4;i++) { cout<<nArray[i]<<","; } cout<<endl; }
-
-
二维数组
-
二维数组的声明和初始化
-
声明如下:
type array[第一维的大小][第二维的大小]
int arr[4][5]; -
初始化:
-
int arr[4][5]={{17,27,36,84,56},{32,34,54,76,12},{13,34,65,78,67},{21,54,67,87,89}};
-
二维数组也可以在声明时初始化,每一行相当于一个一维数组;
-
-
省略第一维的大小
-
二维数组可以省略第一维的大小,但是必须指定第二维的大小;
int arr[][3]=
{
{1,2,3},
{3,4,5}
}; -
编译器可以根据初始化元素胡个数以及第二维的尺寸来推算第一维的大小;
-
注意:下面这种是错误的;
int arr[2][]={1,2,3,4,5,6};
-
-
二维数组元素的访问
-
数组名[一维数组下标][二维数组下标]
-
二维数组的遍历;
for(int row=0;row<3;row++) { for(int col=0;col<2;col++) { cout<<arr[row][col]; } } cout<<"\n";
-
二维数组转为一维数组
-
#include <iostream> using namespace std; int main() { int arr1[3][2]={{1,2},{3,4},{5,6}}; int arr2[6]; for(int row=0;row<3;row++) { for(int cow=0;cow<2;cow++) { arr2[row*2+cow]=arr1[row][cow]; } } for(int i=0;i<6;i++) { cout<<arr2[i]<<"\t"; } }
-
-
-
-
-
只装字符的数组
-
字符数组元素的访问;
数组名[元素序列号]
str[4]; -
#include <iostream> using namespace std; int main() { char str[]="this is c++ program"; int len=sizeof(str); str[5]='*'; for (int i = 0; i < len; ++i) { cout<<str[i]; } }
-
特殊的字符串结束符
-
字符串相当于一个字符数组,不过字符串代表的是常量,而字符数组代表变量,在字符串最后系统会自动添加一个'\0';因为'\0'在ASC||码表中是代表0的字符;从ASC||可以看出,0字符是一个神马都不可以显的字符;是一个空操作符,即表示神马都不干;
-
-
-
-
指针
- 指针变量和指针是两个概念,为了方便记忆,我们可以把指针理解为地址,指针变量就是存储地址值的变量;
-
指针变量的声明:
- 数据类型 * 指针名;
- 如果要声明多个变量:数据类型 * 指针名1,指针名2,.....,;
- int *pn,*pi;
float *pi;
char *pr;
int *(pf)();//这是个指向函数的指针,该函数的返回值为int型数值;
int **pp;//pp是一个指向指针的指针,即二维指针; - 因为指针是变量的地址,所以不同类型的变量的指针所占用的空间大小也是相同的;
- 获取地址与初始化;
- 用&获取地址:&变量名;
int a=10;
int b[5]={1,2,3,4,5};
取变量a的地址用&a,取数组元素b[3]的地址值用&b[3],有了地址值就可以赋值给指针变量,对其进行初始化; - int *pa=&a;//将a的地址赋给存放地址的变量(指针)pa
int *pb=&b[3];//将b[3]的地址赋给存放地址的变量(指针)
这时,pa保存的是变量a的地址值,pb保存的是数组元素b[3]的地址值;由于指针变量只能保存地址,所以不要将任何其他不是地址的值赋值给指针变量; - 特殊的值NULL
- 如果声明指针变量的时候,没有对其初始化,就不能直接使用,应将其指向一个特殊值NULL;
- int *p=NULL;
- 指针的使用
- 规定"*"为指针的间接访问操作符,其作用是间接的访问指针所指向胡变量或内存空间中的数据;
* 指针变量名; -
#include <iostream> using namespace std; int main() { int n=10; int *pn=&n;//把n的地址赋值给指针变量n; cout<<"n="<<n<<endl; cout<<"pn指向的值为:"<<*pn<<endl; n+=25; cout<<"n="<<n<<endl; cout<<"pn指向的值为:"<<*pn<<endl;//引用pn所指向的数值并输出; *pn=*pn*10; cout<<"n="<<n<<endl; cout<<"pn指向的值为:"<<*pn<<endl; }
- 规定"*"为指针的间接访问操作符,其作用是间接的访问指针所指向胡变量或内存空间中的数据;
-
指向指针变量的指针
-
int i=0; int *p=&i; int **pp=&p;
上面的int **pp可以这样理解,其数据类型是int*型,而不是int型,所以pp是指向int型指针的指针变量;对*pp的就是对指针变量p的操作;
#include <iostream> using namespace std; int main() { int n=10,i=18; int *pn=&n; int **pp=&pn; cout<<"n="<<n<<endl; cout<<"pn="<<pn<<endl; cout<<"*pn"<<*pn<<endl; cout<<"pp="<<pp<<endl; **pp=5; cout<<"n="<<n<<endl; *pp=&i; cout<<"pn="<<pn<<endl; cout<<"*pn="<<*pn<<endl; }
-
- 用&获取地址:&变量名;
-
指针变量的操作
-
指针变量的加减法
-
新地址=旧地址+n*指针指向的变量所占用的内存字节数
-
-
指针变量的关系运算
-
-
数组,字符串,指针
- 其实数组名就是数组的首地址;
//证明数组名即为首地址 #include <iostream> using namespace std; int main() { int arr[5]={1,2,3,4,5}; int *p=&arr[0]; cout<<"p="<<p<<endl; cout<<"arr="<<&arr<<endl; }
//用指针改变数组中元素的值 #include <iostream> using namespace std; int main() { int arr[5]={1,3,5,7,9}; int *p=arr; for(int i=0;i<5;i++) { *(p+i)=i*2; cout<<arr[i]<<" "; } cout<<endl; }
-
一维数组中元素的指针表示
-
int arr[5];
arr[i];//用下标的表示方法;
*(arr+i); //用指针的表示方法 -
//两种方式表达数组 #include <iostream> using namespace std; int main() { int arr[5]={1,2,3,4,5}; for(int i=0;i<5;i++) { cout<<"arr["<<i<<"]="<<arr[i]<<endl; cout<<"*(arr+"<<i<<")="<<*(arr+i)<<endl; } }
-
二维数组的指针表示法
-
int arr[3][3];
arr[i][j]'
*(*arr+i)+j);
-
-
-
字符串和指针
-
用字符数组来实现字符串的方式
-
char str[]="this is C++ program"
-
-
用字符指针实现字符串
-
char *pstr
声明字符指针后,可以对其直接赋值初始化
*pstr="this is c++" -
//字符数组和字符指针 #include <iostream> using namespace std; int main() { char *pstr=NULL; char str[]="this is c++"; pstr="this is c++"; cout<<"pstr="<<pstr<<endl; cout<<"str="<<str<<endl; }
-
注意,字符指针如果指向字符串常量,其内容不可以修改,但是如果是指向字符数组是可以修改的;
-
-
-
常量指针与指针常量
-
常量指针
-
const 数据类型 * 指针变量名;
const是标明后面的指针是常量指针,其作用是作用于把指向的数据定义为常量,但并不保证其指向空间地只读性,只保证在指针间接访问时时时其不被修改; -
#include <iostream> using namespace std; int main() { int i=8; int n=18; // const int *p=&i;//常量指针指向变量i; // *p=28;//?修改常量指针指向的数据值,产生编译错误; // cout<<*p<<endl; const int *p=&i; cout<<*p<<endl; i=20;//通过变量名,直接改变变量i的值 cout<<*p<<endl; p=&n; cout<<*p<<endl; }
从上面代码可以看出,常量指针只保证所指向的数据值在使用指针间接访问的时候不会被改变,但不使用指针访问的时候还是可以修改的;
为了解决这种问题,可以把指针所指向的数据也定义为常量,这样,在任何时候都不可以更改;
例如:const int n=100;const int pn=&n;
-
-
指针常量
-
格式:数据类型 * const 指针变量名=&变量名;
其中const在数据类型* 之后,表示指针变量中的地址值是常量;下面错误示例:
int i=8; int n=10; int *const p=&i;//定义一个指针常量并初始化 p=&n;//把指针常量指向别的常量n,产生编译错误;
正确使用:
#include <iostream> using namespace std; int main() { int i=8; int n=10; int * const p=&i;//定义指针常量p,并初始化指向变量i; *p=12;//通过指针常量改变其指向的变量i的值; cout<<*p<<endl; i=i+n;//改变变量i的值; cout<<*p<<endl; }
-
- 常量指针是保证通过指针间接访问的内存中的数据不被修改,而指针常量是保证指针本身不会被修改;
-
-
指针与函数
- 指针作为参数
#include <iostream> using namespace std; void myCopy(int *pDst,const int * pSrc,int len); void disp(const int *p,int len); int main() { int arr1[20]={0}; int arr2[10]={1,2,3,4,5,6,7,8,9,0}; myCopy(arr1,arr2,sizeof(arr2)); disp(arr1,10); } void myCopy(int *pDst,const int * pSrc,int len) { for(int i=0;i<len;i++) { *pDst++=*pSrc++;//把源数组的数据复制给目的数组 } } void disp(const int *p,int len) //函数disp的实现定义 { for(int i=0;i<len;i++) { cout<<*(p+i)<<" ";//打印数组的数据 } cout<<endl; }
-
指针作为返回值
-
这种返回值为指针类型的函数,一般被称为指针函数,声明一个指针函数格式如下:
数据类型 * 函数名(参数表);
int * func(int *a,int b);
其中函数名为func,调用其后可以得到一个指向整数的指针;#include <iostream> using namespace std; int * min(int * arr,int len); int main() { int arr[]={333,22,400,11,38}; int * pMin=NULL;//初始化指针变量pMin pMin= min(arr,5);//调用min得到最小值的地址 cout<<"min="<<*pMin<<endl; } int * min(int * arr,int len) { static int * p=arr;//定义静态指针变量p。并初始化为数组arr首地址 for(int i=1;i<len;i++) { if(*p>*(arr+i)) { p=arr+i; } } return p; }
注意:返回指针给主调函数,只能是函数内声明的静态变量或者在函数外害起作用的变量;
-
-
堆内存(动态内存)
-
堆内存获取并使用
- 使用操作符new申请堆内存空间,不用头文件声明;
格式如下:
new 数据类型[表达式];
其中new为关键字,表明这是一个申请堆内存的操作,申请连续空间时,表达式是一个确定的整整数,可以是常量,也可以是变量,如果只申请一个变量大小的空间,表达式和方括号[]可以省略
new 数据类型; -
#include <iostream> using namespace std; int main() { int *p = NULL; int size = 0; int i = 0; cout<<"请输入需要生成的长度:"; cin>>size; p=new int[size];//申请堆内存,并把返还值给p if(p==NULL) { cout<<"申请空间失败"<<endl; return 0; } for(i=0;i<size;i++) { *(p+i)=i;//把堆内存中申请的空间每一个进行初始化; } for(i=0;i<size;i++) { cout<<*(p+i)<<" ";//输出内存中申请的空间的数据值; } cout<<endl; }
- 使用操作符new申请堆内存空间,不用头文件声明;
-
释放堆内存
-
对于变量和数组,在程序结束运行后,系统会自动回收其占用的空间,但是对于申请的堆内存空间,很多系统不会回收;导致计算机运行越来越慢,这种只申请不释放空间的情况被称为内存泄漏,所以用delete操作符来释放堆内存空间;
-
格式:delete []指针;
其中,delete是关键字,表面这是释放堆内存的操作,[]表示释放的是堆内存中的内存空间,如果申请的只是一个堆内存变量,则[]可以省略;最后的指针是通过new获得的指针; -
#include <iostream> using namespace std; int main() { int *p=NULL; int size=0,i=0,sum=0; cout<<"请输入需要计算的数字个数n:"; cin>>size;//接收堆空间大小变量 p=new int[size]; if(p==NULL) { cout<<"申请空间失败"<<endl; return 0; } cout<<"请连续输入n个整数:"<<endl; for(i=0;i<size;i++) { cin>>*(p+i); sum+=*(p+i); } cout<<"sum="<<sum<<endl; delete p; }
-
-
- 指针作为参数
- 其实数组名就是数组的首地址;
-
结构
-
结构的概念
-
结构类型的声明
-
struct 结构名 { 成员列表 }; //注意分号 struct student { long id; char name[10]; char sex; int age; float score; };
注意对成员都应该进行类型声明,且每个成员类型 声明后应该用分号隔开,整个结构声明的最后也是应该有分号的;
-
-
结构类型变量的定义
-
结构声明后就成为一种自定义的一种新的数据,可以用于变量,数组,指针的定义;
-
struct 结构名 变量名;
struct student sd1,sd2; -
typedef的使用
-
typedef定义新的类型名代替已有的类型名;
typedef 原数据类型名 新数据类型名;
typedef int COUNT;
COUNT i;
-
-
-
结构变量的赋值
-
使用数据集合对结构变量赋值;(已经将struct student 定义为STUDENT)
-
STUDENT sd;
sd={800123;"LiMing",'M',15,89.5};
-
-
逐个成员进行赋值
-
STUDENT sd; sd.id=800123; strcpy(sd.name,"LiMing");//字符数组不可以直接赋值,只能使用字符串复制 sd.sex='M'; sd.age=15; sd.score=89.5;
-
-
-
结构成员的访问
-
#include <iostream> using namespace std; struct student { long id; char name[10]; char sex; int age; float score; }; typedef struct student STUDENT;//定义新的类型名 int main() { STUDENT sd;//定义结构变量 cout<<"请分别输入考生的学号,姓名,性别,年龄,得分"<<endl; cin>>sd.id; cin>>sd.name; cin>>sd.sex; cin>>sd.age; cin>>sd.score; cout<<sd.id<<"\t"<<sd.name<<"\t"<<sd.sex<<"\t"<<sd.age<<"\t"<<sd.score<<endl; }
-
-
枚举类型
-
由若干个有名字的整形变量的集合组成;被称为枚举类型;
-
enum 枚举类型名 {枚举值列表};
enum是关键字,表示定义的是一个枚举类型,枚举名是符合标识符规定的字符组合,枚举值列表是由若干个用标识符表示的整形常量所组成,多个枚举符之间用逗号分隔,枚举值列表中的整形常量又被称为枚举常量; -
enum COLOR_PEN {RED_PEN,YELLOW_PEN,BLUE_PEN};
默认情况下从0开始赋值,并依次加1;
也可以声明时进行赋值
enum COLOR_PEN{RED_PEN=1,YELLOW_PEN=3,BLUE_PEN}; -
注意:枚举常量只能是整型数,不能是其他类型数据;
-
枚举的声明和赋值
-
枚举既然是一种数据类型,也可以用来声明变量
-
枚举类型名 变量名;
COLOR_PIN pen; -
#include <iostream> using namespace std; enum WEEK{SUM,MON,TUE,WED,THU,FRI,SAT}; int main() { WEEK week1,week2,week3; week1=MON; weeek2=WED; week3=SAT; cout<<week1<<""<<week2<<""<<week3<<endl; }
-
-
-
结构类型的数组和指针
- 结构数组
- struct 结构名 结构数组名;
- 直接用struct student声明,或把struct student用typedef定义为STUDENT 后直接用STUDENT来声明的结构数组;
struct student sdarr[3];
STUDENT sdarr[3]; - 初始化
STUDENT sdarr[3]={{800123,"LiMing",'M',16,89.5},{800124,"ZengLu",'F',16,89.5},{800125,"WuMei",'F',16,86.5}}; - 访问:sdarr[2].name;
#include <iostream> using namespace std; struct student { long id; char name[10]; char sex; int age; float score; }; typedef struct student STUDENT;//定义新的类型名 STUDENT sdarr[5]={ {800123,"LiMing",'M',16,89.5}, {800124,"ZengLu",'F',16,95.5}, {800125,"WuMei",'F',16,80}, {800126,"WangLei",'M',16,88.5}, {800127,"SunDong",'M',17,66} };//全局结构数组 bool findStudent(long id ,int &index);//查找函数声明 void disp(int index); int main() { long id=0; int index=0; cout<<"请输入学号:"; cin>>id; if(findStudent(id,index)) { disp(index); } else { cout<<"没有该学生相关记录"<<endl; } } bool findStudent(long id,int &index) { for(int i=0;i<5;i++) { if(sdarr[i].id==id) { index=i; return true; } } return false; } void disp(int index) { cout<<"学号\t姓名\t性别\t年龄\t成绩"<<endl; cout<<sdarr[index].id<<"\t"<<sdarr[index].name<<"\t"<<sdarr[index].sex<<"\t"<<sdarr[index].age<<"\t"<<sdarr[index].score<<endl; }
-
结构指针
-
struct 结构名 *p;//用struct student来声明
STUDENT *p;//用STUDENT来声明; -
#include <iostream> using namespace std; struct student { long id; char name[10]; char sex; int age; float score; }; typedef struct student STUDENT;//定义新的类型名 int main() { STUDENT *p=NULL;//声明结构指针 STUDENT sd={800123,"LiMing",'M',16,89.5}; p=&sd;//把指针指向结构变量sd; p->age=18;//改变变量中成员值age p->score=86.5; cout<<"学号\t姓名\t性别\t年龄\t成绩"<<endl; cout<<p->id<<"\t"<<p->name<<"\t"<<p->sex<<"\t"<<p->age<<"\t"<<p->score<<endl; }
定义好一个结构变量后,如果用结构指针指向其所在的地址。实质上就是指针指向结构变量的第一个成员的起始地址,和数组类似;
-
- 结构数组
-
结构和函数
-
结构作为参数
-
传数值调用
#include <iostream> #include <cstring> using namespace std; struct user { char name[10]; int age; }; typedef struct user USER;//重新定义新结构类型名 void func(USER us); int main() { USER user1={"LiLei",15}; func(user1);//传数值调用函数; cout<<"姓名:"<<user1.name<<"年龄:"<<user1.age<<endl; } void func(USER us) { us.age+=2; strcpy(us.name,"HAHA"); }
- 从最终的结果可以看出,改变形参并不影响实参;我们会发现,应该采用传递地址调用,将结构变量的首成员地址传递给结构指针类型的实际参数,改变形参中成员的数据将会影响到实参;
-
传地址调用
#include <iostream> #include <cstring> using namespace std; struct user { char name[10]; int age; }; typedef struct user USER;//重新定义新结构类型名 void func(USER *pUser); int main() { USER user1={"LiLei",15}; func(&user1);//调用时把结构变量成员首成员的地址给形参; cout<<"姓名:"<<user1.name<<"年龄:"<<user1.age<<endl; } void func(USER *pUser) { pUser->age+=2; strcat(pUser->name,"HAHA"); }
-
引用调用
是给结构实参的别名,对形参的操作将会影响到实参;#include <iostream> #include <cstring> using namespace std; struct user { char name[10]; int age; }; typedef struct user USER;//重新定义新结构类型名 void func(USER &us); int main() { USER user1={"LiLei",15}; cout<<"姓名:"<<user1.name<<"\t年龄:"<<user1.age<<endl; func(user1);//函数的引用调用 cout<<"姓名:"<<user1.name<<"\t年龄:"<<user1.age<<endl; } void func(USER &us) { us.age+=2; strcat(us.name,"HAHA"); }
-
-
结构作为返回值
-
#include <iostream> using namespace std; struct man { char name[10]; int age; char sex; }; typedef struct man MAN;//定义struct man为MAN; MAN GetMan();//声明函数,其返回值为MAN; void disp(MAN *p); int main() { MAN manarr[3];//定义struct man型数组; for(int i=0;i<3;i++) { manarr[i]=GetMan();//调用Getman()接收输入; disp(&manarr[i]);//显示 } } void disp(MAN *p) { cout<<"姓名:"<<p->name<<"\t"<<"年龄:"<<p->age<<"\t"<<"性别:"<<p->sex<<endl; } MAN GetMan() { MAN t;//声明结构的临时变量; cout<<"请输入该人的姓名,年龄和性别,中间用空格隔开:"; cin>>t.name>>t.age>>t.sex; return t; }
-
-
-
结构中的结构
- 指针变量作为结构成员
-
#include <iostream> using namespace std; struct sstr { int *pn; char *pstr; }; int main() { int i=10; struct sstr t; t.pn=&i; t.pstr="abcdefg"; cout<<*t.pn<<endl; cout<<t.pstr<<endl; }
-
结构变量作为结构成员
-
#include <iostream> using namespace std; struct SScore { int num; float score; }; struct SMan { int id; char sex; int age; }; struct SStudent { struct SScore score; struct SMan man; int arr[5]; }; int main() { struct SStudent student; student.score.num=10; student.man.age=19; cout<<student.score.num<<" "<<student.man.age<<endl; }
向上面这样,SStudent结构中包含了SScore结构的变量score和SMan结构的变量man;
-
-
- 指针变量作为结构成员