2024-01-03
一、指针数组
-
数组元素是指针的数组是指针数组,
-
// 语法规范: 类型名 * 数组名【数组长度】
int arr[2][3] =
{
{10,20,30},
{40,50,60}
};
int* p[2];
p[0] = arr[0];
p[1] = arr[1];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
cout << *(p[i]+j)<<" ";
}
cout << endl;
}
二、多级指针
-
如果一个指针变量保存的是另外一个指针变量的地址,我们称之为多级指针,或者纸箱指针的指针
-
p1, ** p2;
-
*int a, * p1, ** p2; p1 = &a; p2 = &p1; **p2 = 100; cout << "&a=" << &a <<"\tp1=" << p1 << "\tp2=" << p2 << endl; cout << "a=" << a << "\t*p1=" << *p1 << "\t**p2=" << **p2 << endl;*/
//二维数组地址问题
``` int arr[2][3] = { {10,20,30}, {40,50,60} }; // arr+1 arr[1]和arr[1][0]都是第二行的首地址 cout << arr+1 <<"\t" << arr[1] << "\t" << &arr[1][0] << endl; // **arr 等于 *arr[0] for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { cout << *(*(arr+i)+j)<<endl; } } for (int i = 0; i < 6; i++) { cout << *(*arr+i) << endl; } ```
-
三、数组指针
* 语法规范: 数据类型(*指针变量名)[长度]
int(*p)[5];// 定义一个数组指针,可以指向一个具有五个int类型的元素的数组
int arr[5] = { 10,20,30,40,50 };
// 使用&arr为p进行赋值,而不能使用arr对p进行赋值
cout << arr << "\t" << &arr << endl;
//虽然arr和&arr的地址是一样的,但是含义不同,arr代表的数组第一个元素的首地址,&arr才是整个数组的地址
p = &arr;
for (int i = 0; i < 5; i++)
{
cout << (*p)[i]<<"\t";
}
-
指针数组和数组指针的总结:
从概念上进行区分:
指针数组本质上是一个数组,数组里面元素是指针;
数组指针本质上是一个指针,是要指向整个数组;
从运算符的优先级上进行区分:
指针数组:
int p[10]; 因为[]的优先级比的优先级高,所以是先有数组,然后才有int类型的指针变量的数组元素
数组指针:int (*p)[10]; 因为()的优先级更高,所以是先获取指针,然后再让这个指针指向整个数组。
四、指针常量和常量指针
-
常量指针:指针指向的内存地址中的内容不是不可以的修改的
const 数据类型 * 指针名=地址;
int a = 10, b = 20;
const int* p = &a;
//p = &b;
// 常量指针的指向内容不可以修改
*p = 100;
cout << *p << endl; -
指针常量:指针的指向不可以修改,但是指向的内存中的只可以修改
int * const p= 地址
int a = 10, b = 20;
int * const p = &a;
// 指针常量的指向不可以修改
//p = &b;
*p = 100;
cout << *p << endl;
char ch[] = "dasfa";
int arr[] = { 1,2,3,4 };
char* p = ch;// p=&ch
int* q = arr;// q=&arr
for (int i = 0; i < strlen(ch); i++)
{
cout << *(p + i);
}
for (int i = 0; i < 4; i++)
{
cout << *(q + i);
}
五、动态内存分配
-
程序在运行的时候可以使用malloc和new来进行内存的申请,程序员要自己负责使用free或delete来释放内存
// new来进行内存分配
// 语法:单个内存分配 new 类型名(初始值); 多个内存空间的分配:new 类型名[整型表达式];
// 释放内存:释放单个内存 delete 指针名; 多个内存释放 delete[] 指针名;
// 分配单个内存
int* p1 = new int(10);
cout << *p1 << endl;
// 分配多个内存空间,分配连续的10个int类型的内存单元
int* p2 = new int[10];
// 释放单个内存空间
delete p1;
// 释放多个内存空间
delete[] p2;
// 释放完成之后,将其置为空指针,会避免野指针的报错(p = NULL);
p2=NULL;
六、引用
- 引用的概念:引用是对已有变量或者表达式的一种别名机制,主要用在函数的形参和返回值
- 作用:给变量起别名
- 语法:数据类型&别名=原名;
- 本质是一个指针常量(里面的内容不能改变) int *const p=&a
- 引用的注意事项:
1、引用必须要进行初始化
2、引用初始化后不可改变
```
int a = 10,c=20;
int& b = a;
cout << a << "\t" << b << endl;
b = 100;
/*
b初始化不能不能作为其他变量名命名
b = c;
*/
cout << a << "\t" << b << endl;
// 本质是一个指针常量(里面的内容不能改变) int *const p=&a;
int* const p = &a;
int& ref = a;
```
七、参数的使用
1.函数的基本使用:
-
函数的概念:在程序设计的时候,如果一段代码重复进行某个操作或者完成某 - 项功能,这样的代码组织就叫做函数
//函数的定义 : 函数类型函数名(形参) { 函数体 };
//函数的调用:函数名(实参);
//函数类型和返回值:
//函数可以有返回值也可以没有
//函数的类型就是函数返回值的类型,可以是任何一种类型
//函数的返回值由函数体中的return语句给出
//如果函数没有返回值,函数的类型void来定义
//函数参数 :
//形参(形式参数) : 定义函数的时候括号中写的参数
//实参(实际参数) : 调用函数的时候括号中写的参数
2、参数问题
-
地址传递
// 指针作为函数的形参
// 指针作为函数的参数的时候会改变实参的值,
// 因为形参的指针变量和实参指的是同一块内存空间,所以对于指针变量的操作,实际上就是对于实参的操作。
// 引用作为函数的形参会影响实参的值
// 因为引用是一种别名机制,对于引用形参的操作实际上就是对于实参的操做
引用参数和数值参数的比较:
//引用作为函数的参数的时候,调用的时候的实参只能是变量,如果数值作为函数的形参,那么实参可以是变量、也可以是常量或者表达式。
// 引用传递,实参只能是变量
// 数组作为函数的参数的时候实际上传递的是数组的首地址
// 字符指针作为函数的参数,接受的是字符数组的首地址
八、全局变量
-
变量的生命周期
// 每一个标识符都有自己的特定的作用范围,也就是自己的生命周期,如果超过这个范围就会被自动销毁。
全局变量:在函数的外部进行定义的变量,会在函数的范围外和范围内都能使用。
局部变量:函数中定义的变量,只能在当前的函数里使用,如果超过函数的范围就会失效。
九、函数的存储类别
静态存储和动态存储
-
动态变量 数据类型 * 数据名= new int();
-
静态变量 static 数据类型 数据名
-
静态变量只初始化一次
十、内联函数和重载函数
- 内联函数通常用于小而简单的函数,以减少函数调用的开销,提高程序的执行效率。
内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展)
// 声明内联函数
inline int add(int a, int b) {
return a + b;
}
int main() {
int result = add(3, 4); // 函数调用被编译器替换为表达式 3 + 4
std::cout << "Result: " << result << std::endl;
return 0;
}
- 重载函数:C++中可以定义同名参数,只要他们的形参 类型或者个数不同
int getMin(int a, int b,int c)
{
return a < b ? (a<c?a:c) :( b<c?b:c);
}
int getMin(int a, int b)
{
return a < b ? a : b;
}
十一、函数的默认参数:
在定义函数的时候,可以预先给函数的形参来指定默认值,
在函数调用的时候如果传递了实参就使用实参,如果没传递就用形参的默认值即可
默认的形参的默认值的顺序必须要从右向左进行定义,如果某个形参有默认值,那么它右边的所有形参必须都有默认
int getSum(int x, int n=2)
{
int k = 1;
for (int i = 0; i < n; i++)
{
k *= x;
}
return k;
}
十二、函数指针的使用:
-
我们需要定义可以直接保存函数指针变量来保存
-
语法规范: 函数类型(函数指针名)(参数类型列表)
*/
//定义函数指针变量
int (*fp)(int, int,int); -
函数的嵌套调用:
//在C + +中函数的定义都是相互独立的,不允许在一个函数中定 义另外一个函数,
//但是允许在一个函数中调用另外一个函数。
int fun02(int x)
{
int c = 1;
for (int i = 1; i <= x; i++)
{
c = c * i;
}
return c;
}
int fun01(int n)
{
int s = 0;
for (int i = 1; i <= n; i++)
{
s = s + fun02(i);
}
return s;
}
十三、结构体:
-
、结构体:
struct 结构名
{
数据类型1:成员名;
数据类型2: 成员名2
}*/
* //定义结构体来储存学生信息 //struct score //{ // double Chinese; // double Math; // //}; typedef struct student { int Id; string Name; double score; }Stu; /* * 结构体名称 * 1.typedef struct student stu; * 2 后面 stu; * 3.student stu; * 结构体指针 */ struct dog* p { }; double aver(Stu* p) { double sum = 0; for (int i = 0; i < 5; i++) { cout << "Id=" << p[i].Id << "\tName=" << p[i].Name << "\tscore=" << p[i].score << endl; sum += (p+i)->score; } return sum/ 5; } /*
十四、联合:
有时候需要使用几个不同的变量占用同一块内存空间,就可以定义一 个联合来实现,联合也叫做共用体。
语法: union联合名{数据类型1成员名1;数据类型2成员名..};
联合体中的所有成员变量共用一块内存空间,如果对一个成员的值进行修改,那么也会同时影响其他的成员的值。
因为联合体中的所有成员都是占用同一块空间的,所以联合体的大小就是所有成员中占用最大内存的成员的大小。
*/
union myData
{
int i;
char ch;
}md;
/*
十五、枚举
- 枚举是用标识符来表示整型常量的集合,使用enum来定义
- 枚举类型语法: enum 枚举类型名{枚举类型1,枚举类型…];.
- 枚举类型中元素的起始值如果不指定,将自动从0开始为各个枚举元素进行初值的赋值,后面枚举元素依次加1
enum weekday {Sun=7,Mon=1,Tue,Wed,Thu,Fri,Sat};
十六、命名空间
-
如果大型程序需要程序员来进行维护,为了避免出现标识符冲突问题
-
注意:
-
命名空间只可以在全局范围进行定义,但是可以嵌套
-
定义一个命名空间实际上就是定义-个域,命名空间中的所有内容都局限于该空间中。命名空间的定义
只影响使用,不影响生命周期。定义命名空间需要使用namespace 关键字。后跟空间名字,然后接一对
{}即可, {}中即为命名空间中的成员。
```
namespace NameSpace1
{
int a = 10;
void fun(int x,int y)
{
cout << "namespace1函数" << endl;
cout << x*y << endl;
}
}
namespace NameSpace2
{
int fun(int x, int y);
namespace ns3
{
int fun(int x, int y);
}
}
namespace ns1 = NameSpace1;
namespace ns2 = NameSpace2;
int ns2::fun(int x, int y)
{
return x - y;
}
int ns2::ns3::fun(int x, int y)
{
return x + y;
}
int main()
{
cout << ns2::fun(10, 20) << endl;
cout << ns2::ns3::fun(10, 20);
return 0;
}
```
十七、文件分层处理
- 头文件:一般存放的是结构体的定义、函数的原型(声明)、全局常量,还有类等等。
- 源文件:存放的是函数的定义,还有其他的一些功能等。
多文件实现的案例:
编写一个处理平面图形的程序
设计一个表示图形中心点的结构体Point,有两个int类型的成员来表示点的坐标
设计一个表示圆的结构体Circle,包含个Point成员表示圆心, 还有一个double成员表示半径
设计一个表示矩形的结构体Rectangle,包含一个Point成员矩形的图形中心, 还有两个double类型的成员表示矩形的长和宽。
要求:能够计算两个图形的面积和周长。
Point.h: Point结构体的定义
Circleh: Circle结构体的定 义以及与Circle相关的函数原型(声明)
Rectangle.h: Rectangle结构体的定义以及与Rectangle相关的函数原型(声明)
Circle.cpp:与Circle相关的函数定义
Rectangle.cpp:与Rectangle相关的函数定义
Main.cpp:主函数所在的文件
Main()函数
#include<iostream>
#include"Circle.h"
#include"Rectangle.h"
using namespace std;
int main()
{
struct Circle c = { {10,20},10 };
cout <<"圆的面积:" << sC(c) << endl;
cout << "圆的周长:" << cC(c) << endl;
struct Rectangle re = { {10,20},10 ,20};
cout << "矩形的面积:" << sJ(re) << endl;
cout << "矩形的周长:" << cJ(re) << endl;
return 0;
}
头文件:
//#pragma once
#ifndef Point_H
#define Point_H
struct Point
{
int x;
int y;
};
#endif
#pragma once
#include "Point.h"
struct Circle
{
Point point;
double r; //半径
};
double sC(struct Circle);
double cC(struct Circle);
源文件
#include"Circle.h"
double sC(struct Circle c)
{
double π = 3.14;
return π * c.r *c.r;
}
double cC(struct Circle c)
{
double π = 3.14;
return π * c.r * 2;
}