C++语法:指针、结构体
C++ (一):常量、变量、关键字、标识符、数据类型(整形、浮点型、字符型、字符串型、布尔型)
C++ (二):选择、循环、嵌套、跳转语句
C++ (三):数组、函数
C++ (四):指针、结构体
指针
- 指针概念
指针的作用:可以通过指针间接访问内存。
- 内存编号是从0开始记录的,一般用十六进制数字表示。
- 可以利用指针变量保存地址。
- 指针变量定义和使用
指针变量定义语法:数据类型 * 变量名;
#include <iostream>
using namespace std;
int main()
{
//1、定义指针
int a = 10;
//指针定义的语法:数据类型 * 指针变量
int * p; //创建p为指针变量
//让指针记录变量a的地址
p = &a; // &为取址符号
cout << "a的地址为:" << &a << endl; //a的地址为:00FBFC78
cout << "指针p为:" << p << endl; // 指针p存储的值 和变量a的地址是一样的 //指针p为:00FBFC78
//2、使用指针
//可以通过解引用的方式来找到指针指向的内存
//指针前加 * 代表解引用,找到指针指向的内存中的数据
*p = 1000; //通过*p访问内存,并修改内存的值
cout << "a= " << a << endl; //a= 1000
cout << "*p:" << *p << endl; //*p:1000
system("pause"); //按任意键继续
return 0;
}
- 指针所占内存空间
- 在32位操作系统下,不管什么类型的指针都占4个字节的内存。
- 在64位操作系统下,不管什么类型的指针都占8个字节的内存。
#include <iostream>
using namespace std;
int main()
{
//指针所占内存空间
int a = 10;
/*
int * p; //p变量是 int * 数据类
p = &a;
等价于:
int * p = &a;
*/
int * p = &a;
cout << "sizeof(int * )= " << sizeof(p) << endl; //sizeof(int * )= 8 我的操作系统是64位的。
cout << "sizeof(int * )= " << sizeof(int(*)) << endl; //sizeof(int * )= 8
cout << "sizeof(float * )= " << sizeof(float(*)) << endl; //sizeof(float * )= 8
cout << "sizeof(double * )= " << sizeof(double(*)) << endl; //sizeof(double * )= 8
cout << "sizeof(char * )= " << sizeof(char(*)) << endl; //sizeof(char * )= 8
system("pause"); //按任意键继续
return 0;
}
- 空指针
指针变量指向内存中编号为0的空间。
用途:初始化指针变量。
空指针指向的内存是不可以访问的。
#include <iostream>
using namespace std;
int main()
{
//空指针
//1、空指针用于给指针变量进行初始化
int* p = NULL;
//2、空指针是不可以进行访问的
//0~255之间的内存编号是系统占用的,因此不可以访问。
*p = 100; //对空指针解引用,然后操作它,这样是报错的
system("pause"); //按任意键继续
return 0;
}
- 野指针
野指针:指针变量指向非法的内存空间。
野指针和空指针都不是我们申请的空间,所以不要访问。
例如,创建了一个整型变量a,是申请了一个整型变量的空间,由于是申请的空间,所以可以通过指针访问它。
#include <iostream>
using namespace std;
int main()
{
//野指针
int* p = (int*)0x1100; // 0x1100是一个十六进制数,int*使得十六进制数强行转换为地址。
// 拿指针随便指向并没有申请这个内存的访问权限的内存。
cout << *p << endl; // 报错,地址并没有申请,你还要去访问它,就会报错
system("pause");
return 0;
}
- const修饰指针
看const右侧紧跟着的是指针还是常量,是指针就是常量指针,是常量就是指针常量。
- 如果 const后面跟的是指针(),就不能做 p=20 操作,即不能修改指针指向的值。
- 如果const 后面跟的常量(p),就不能做 p = &b 操作,即不能修改指针的指向。
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = 10;
//1、const修饰指针 常量指针
const int* p = &a; // const(常量) *(指针) → 常量指针
// *p = 20; 错误,常量指针 → 指针指向的值不可以改,指针的指向可以改
p = &b; // 正确
//2、const修饰指针 指针常量
int* const p2 = &a; // *(指针)const(常量) → 指针常量
*p2 = 100; //正确的
p2 = &b; //错误,指针的指向不可以改,指针指向的 值可以改
//3、const修饰指针和常量
const int* const p3 = &a;
*p3 = 100; //错误
p3 = &b; //错误
system("pause");
return 0;
}
- 指针和数组
利用指针访问数组中元素。
#include <iostream>
using namespace std;
int main()
{
//指针和数组
//利用指针访问数组中的元素
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
cout << "第一个元素为:" << arr[0] << endl;
int* p = arr; //数组名arr就是数组的首地址
cout << "利用指针访问第一个元素:" << *p << endl;
p++;
cout << "利用指针访问第二个元素:" << *p << endl;
cout << "利用指针遍历数组:" << endl;
int* p2 = arr;
for (int i = 0; i < 10; i++)
{
//cout << arr[i] << endl;
cout << *p2 << endl;
p2++;
}
system("pause");
return 0;
}
输出:
第一个元素为:1
利用指针访问第一个元素:1
利用指针访问第二个元素:2
利用指针遍历数组:
1
2
3
4
5
6
7
8
9
10
请按任意键继续. . .
- 指针和函数
利用指针作函数的参数,可以修改实参的值。
地址传递可以改变实参的数据,值传递不可以改变实参的值。
如果不想修改实参,就用值传递,如果想修改实参,就用地址传递。
代码例子中,temp的值会传递给 *p2 地址中的值,所以a、b实参的值改变了。
#include <iostream>
using namespace std;
void swap(int* p1, int* p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main()
{
//指针和函数
int a = 10;
int b = 20;
swap(&a, &b);
//如果是地址传递,可以修改实参,原来 a = 10;b = 20,地址传递后 a = 20,b = 10.
cout << "a =" << a << endl; //a=20
cout << "b =" << b << endl; //a=10
//如果是值传递,不可以修改实参,原来 a = 10;b = 20,值传递后 a = 10,b = 20.
system("pause");
return 0;
}
- 指针配合数组和函数案例
案例描述:封装一个函数,利用冒泡排序,实现对整型数字的升序排列。
例如: int arr[10] = {4,3,6,9,1,2,10,8,7,5}
#include <iostream>
using namespace std;
//冒泡排序函数
void bubbleSort(int * arr, int len)
{
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - i - 1; j++)
{
//如果j>j+1的值,交换数字
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//打印数组
void printArray(int* arr, int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << endl;
}
}
int main()
{
//1、先创建数组
int arr[10] = { 4,3,6,1,2,9,10,8,7,5 };
//数组长度
int len = sizeof(arr) / sizeof(arr[0]);
//2、创建函数,实现冒泡排序
bubbleSort(arr, len);
//3、打印排序后的数组
printArray(arr, len);
system("pause");
return 0;
}
运行结果:
1
2
3
4
5
6
7
8
9
10
请按任意键继续. . .
结构体
结构体
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。
- 结构体定义和使用
语法:struct 结构体名 { 结构体成员列表 }
通过结构体创建变量的方式有三种:
- struct 结构体名 变量名
- struct 结构体名 变量名 = { 成员1值,成员2值 }
- 定义结构体时顺便创建变量
结构体变量利用点.访问成员
方法1,方法2:
#include <iostream>
using namespace std;
#include <string>
//自定义数据类型,一些类型的集合组成一个类型
//语法 struct 类型名称 { 成员列表 }
//结构体定义的时候,struct关键字不能省略
//1、创建学生数据类型:学生包括(姓名,年龄,分数)
struct Student
{
//成员列表
//姓名
string name;
//年龄
int age;
//分数
int score;
};
int main()
{
//方法1: struct Student s1; s1类似结构体的实例值,类似变量赋值:int a = 10 → 属性 变量 变量值
//结构体创建的时候,struct 关键字可以省略;上面结构体定义的时候 struct 可以省略
struct Student s1;
//给s1属性赋值,通过点.访问结构体变量中的属性
s1.name = "张三";
s1.age = 18;
s1.score = 100;
cout << "姓名:" << s1.name << "年龄:" << s1.age << "分数:" << s1.score << endl;
//方法2: struct Student s2 = { ... }
struct Student s2 = { "李四",19,80 };
cout << "姓名:" << s2.name << "年龄:" << s2.age << "分数:" << s2.score << endl;
system("pause");
return 0;
}
运行结果:
姓名:张三年龄:18分数:100
姓名:李四年龄:19分数:80
请按任意键继续. . .
方法3:创建结构体的时候,顺便创建个结构体变量
#include <iostream>
using namespace std;
#include <string>
//自定义数据类型,一些类型的集合组成一个类型
struct Student
{
//成员列表
//姓名
string name;
//年龄
int age;
//分数
int score;
}s3; //方法3: 创建结构体的时候,顺便创建个结构体变量
int main()
{
//方法3
s3.name = "王五";
s3.age = 20;
s3.score = 60;
cout << "姓名:" << s3.name << "年龄:" << s3.age << "分数:" << s3.score << endl;
system("pause");
return 0;
}
运行结果:
姓名:王五年龄:20分数:60
请按任意键继续. . .
- 结构体数组
作用:将自定义的结构体放入到数组中方便维护。
语法:struct 结构体名 数组名[元素个数] = { {},{},...,{} }
#include <iostream>
using namespace std;
#include <string>
//自定义数据类型,一些类型的集合组成一个类型
struct Student
{
//成员列表
//姓名
string name;
//年龄
int age;
//分数
int score;
};
int main()
{
//2、创建结构体数组
struct Student stuArray[3] =
{
{"张三",18,100},
{"李四",28,99},
{"王五",38,66}
};
//3、给结构体数组中的元素赋值
stuArray[2].name = "赵六";
stuArray[2].age = 80;
stuArray[2].score = 60;
//4、遍历结构体数组
for (int i = 0; i < 3; i++)
{
cout << "姓名:" << stuArray[i].name << "年龄:" << stuArray[i].age << "分数:" << stuArray[i].score << endl;
}
system("pause");
return 0;
}
运行结果:
姓名:张三年龄:18分数:100
姓名:李四年龄:28分数:99
姓名:赵六年龄:80分数:60
请按任意键继续. . .
- 结构体指针
作用:通过指针访问结构体中的成员。
利用操作符 · >
可以通过结构体指针访问结构体属性。
#include <iostream>
using namespace std;
#include <string>
//结构体指针
//定义学生结构体
struct Student
{
string name; //姓名
int age; //年龄
int score; //分数
};
int main()
{
// 1、创建学生结构体变量,这里的 struct 可以省略
struct Student s = { "张三",18,100 };
//2、通过指针指向结构体变量
struct Student* p = &s; //对s取地址, tudent * p 类似 int * p,这里的 struct 可以省略
//3、通过指针访问结构体变量中的数据
//通过结构体指针 访问结构体中的属性,需要利用'->'
cout << "姓名:" << p->name << "年龄:" << p->age << "分数:" << p->score << endl; //姓名:张三年龄:18分数:100
system("pause");
return 0;
}
- 结构体嵌套结构体
结构体中的成员可以是另一个结构体。
#include <iostream>
using namespace std;
#include <string>
//因为老师的结构体里有学生的结构体,所以学生结构体要在老师结构体前面先定义
//定义学生结构体
struct student
{
string name; //姓名
int age; //年龄
int score; //分数
};
//定义老师结构体
struct teacher
{
int id; //教师编号
string name; //教师姓名
int age; //年龄
struct student stu; //学生结构体
};
int main()
{
//结构体嵌套结构体
//创建老师
teacher t;
t.id = 10000;
t.name = "老王";
t.age = 50;
t.stu.name = "小王";
t.stu.age = 20;
t.stu.score = 60;
cout << "老师姓名:" << t.name << "老师编号:" << t.id << "老师年龄:" << t.age
<< "老师辅导的学生姓名:" << t.stu.name << "学生年龄:" << t.stu.age
<< "学生考试分数:" << t.stu.score << endl;
//老师姓名:老王 老师编号:10000 老师年龄:50 老师辅导的学生姓名:小王 学生年龄:20 学生考试分数:60
system("pause");
return 0;
}
- 结构体做函数参数
作用:将结构体作为参数向函数中传递,传递方式有两种。
传递方式有两种:
- 值传递
- 地址传递
#include <iostream>
using namespace std;
#include <string>
//定义学生结构体
struct student
{
string name; //姓名
int age; //年龄
int score; //分数
};
//定义老师结构体
struct teacher
{
int id; //教师编号
string name; //教师姓名
int age; //年龄
struct student stu; //学生结构体
};
//打印学生信息的函数
//1、值传递
void printStudent1(struct student s)
{
cout << "子函数 值传递前 姓名:" << s.name << "年龄:" << s.age << "分数:" << s.score << endl;
s.age = 100;
}
//2、地址传递
void printStudent2(struct student* p)
{
cout << "子函数 地址传递前 姓名:" << p->name << "年龄:" << p->age << "分数:" << p->score << endl;
p->score = 90;
}
int main()
{
//结构体做函数参数
//将学生传入到一个参数中,打印学生身上的所有信息
//创建结构体变量
struct student s;
s.name = "张三";
s.age = 20;
s.score = 85;
cout << "main函数 传递前 姓名:" << s.name << "年龄:" << s.age << "分数:" << s.score << endl;
printStudent1(s);
cout << "子函数 值传递后 姓名:" << s.name << "年龄:" << s.age << "分数:" << s.score << endl;
printStudent2(&s);
cout << "子函数 地址传递后 姓名:" << s.name << "年龄:" << s.age << "分数:" << s.score << endl;
cout << "main函数 传递后 姓名:" << s.name << "年龄:" << s.age << "分数:" << s.score << endl;
system("pause");
return 0;
}
运行结果:
main函数 传递前 姓名:张三年龄:20分数:85
子函数 值传递前 姓名:张三年龄:20分数:85
子函数 值传递后 姓名:张三年龄:20分数:85
子函数 地址传递前 姓名:张三年龄:20分数:85
子函数 地址传递后 姓名:张三年龄:20分数:90
main函数 传递后 姓名:张三年龄:20分数:90
请按任意键继续. . .
- 结构体中const使用