C++面向过程

2023-05-16

参考文档:C++教程

C++ 简介

概述

C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。

C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。

**注意:**使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。

面向对象

C++ 完全支持面向对象的程序设计,包括面向对象开发的四大特性:

  • 封装
  • 数据隐藏
  • 继承
  • 多态

标准库

标准的 C++ 由三个重要部分组成:

  • **核心语言:**提供了所有构件块,包括变量、数据类型和常量,等等。
  • **C++ 标准库:**提供了大量的函数,用于操作文件、字符串等。
  • **标准模板库(STL):**提供了大量的方法,用于操作数据结构等。

ANSI 标准

ANSI 标准是为了确保 C++ 的便携性 —— 您所编写的代码在 Mac、UNIX、Windows、Alpha 计算机上都能通过编译。

由于 ANSI 标准已稳定使用了很长的时间,所有主要的 C++ 编译器的制造商都支持 ANSI 标准。

C++数据类型

内置类型

C++ 为程序员提供了种类丰富的内置数据类型和用户自定义的数据类型。下表列出了七种基本的 C++ 数据类型:

类型关键字
布尔型bool
字符型char
整型int
浮点型float
双浮点型double
无类型void
宽字符型wchar_t

一些基本类型可以使用一个或多个类型修饰符进行修饰:

  • signed
  • unsigned
  • short
  • long

下表显示了各种变量类型在内存中存储值时需要占用的内存,以及该类型的变量所能存储的最大值和最小值。

类型范围
char1 个字节-128 到 127 或者 0 到 255
unsigned char1 个字节0 到 255
signed char1 个字节-128 到 127
int4 个字节-2147483648 到 2147483647
unsigned int4 个字节0 到 4294967295
signed int4 个字节-2147483648 到 2147483647
short int2 个字节-32768 到 32767
unsigned short int2 个字节0 到 65,535
signed short int2 个字节-32768 到 32767
long int8 个字节-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
signed long int8 个字节-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
unsigned long int8 个字节0 to 18,446,744,073,709,551,615
float4 个字节+/- 3.4e +/- 38 (~7 个数字)
double8 个字节+/- 1.7e +/- 308 (~15 个数字)
long double16 个字节+/- 1.7e +/- 308 (~15 个数字)
wchar_t2 或 4 个字节1 个宽字符

**注意:**不同系统会有所差异。

typedef 声明

您可以使用 typedef 为一个已有的类型取一个新的名字。下面是使用 typedef 定义一个新类型的语法:

typedef type newname; 

例如,下面的语句会告诉编译器,feet 是 int 的另一个名称:

typedef int feet;

现在,下面的声明是完全合法的,它创建了一个整型变量 distance:

feet distance;

枚举类型

枚举类型声明一个可选的类型名称和一组标识符,用来作为该类型的值。其带有零个或多个标识符可以被用来作为该类型的值。每个枚举数是一个枚举类型的常数。

创建枚举,需要使用关键字 enum。枚举类型的一般形式为:

enum enum-name { list of names } var-list; 

在这里,enum-name 是枚举类型的名称。名称列表 { list of names } 是用逗号分隔的。

例如,下面的代码定义了一个颜色枚举,变量 c 的类型为 color。最后,c 被赋值为 “blue”。

enum color { red, green, blue } c;
c = blue;

默认情况下,第一个名称的值为 0,第二个名称的值为 1,第三个名称的值为 2,以此类推。但是,您也可以给名称赋予一个特殊的值,只需要添加一个初始值即可。例如,在下面的枚举中,green 的值为 5。

enum color { red, green=5, blue };

在这里,blue 的值为 6,因为默认情况下,每个名称都会比它前面一个名称大 1。

C++ 变量

变量作用域

作用域是程序的一个区域,一般来说有三个地方可以声明变量:

  • 在函数或一个代码块内部声明的变量,称为局部变量
  • 在函数参数的定义中声明的变量,称为形式参数
  • 在所有函数外部声明的变量,称为全局变量

在程序中,局部变量和全局变量的名称可以相同,但是在函数内,局部变量的值会覆盖全局变量的值。

变量初始化

当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动初始化为下列值:

数据类型初始化默认值
int0
char‘\0’
float0
double0
pointerNULL

正确地初始化变量是一个良好的编程习惯,否则有时候程序可能会产生意想不到的结果。

C++ 常量

定义常量

在 C++ 中,有两种简单的定义常量的方式:

  • 使用 #define 预处理器。
  • 使用 const 关键字。

常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量

常量可以是任何的基本数据类型,可分为整型数字、浮点数字、字符、字符串和布尔值。

常量就像是常规的变量,只不过常量的值在定义后不能进行修改。

**注意:**把常量定义为大写字母形式,是一个很好的编程实践。

常量类型

整数常量

整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。

整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。

浮点常量

浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。

当使用小数形式表示时,必须包含小数点、指数,或同时包含两者。当使用指数形式表示时,必须包含整数部分、小数部分,或同时包含两者。带符号的指数是用 e 或 E 引入的。

布尔常量

布尔常量共有两个,它们都是标准的 C++ 关键字:

  • true 值代表真。
  • false 值代表假。

我们不应把 true 的值看成 1,把 false 的值看成 0。

字符常量

字符常量是括在单引号中。如果常量以 L(仅当大写时)开头,则表示它是一个宽字符常量(例如 L’x’),此时它必须存储在 wchar_t 类型的变量中。否则,它就是一个窄字符常量(例如 ‘x’),此时它可以存储在 char 类型的简单变量中。

字符常量可以是一个普通的字符(例如 ‘x’)、一个转义序列(例如 ‘\t’),或一个通用的字符(例如 ‘\u02C0’)。

在 C++ 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。

字符串常量

字符串字面值或常量是括在双引号 “” 中的。一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。

您可以使用空格做分隔符,把一个很长的字符串常量进行分行。

C++ 修饰符类型

C++ 允许在 char、int 和 double 数据类型前放置修饰符。修饰符用于改变基本类型的含义,所以它更能满足各种情境的需求。

下面列出了数据类型修饰符:

  • signed
  • unsigned
  • long
  • short

修饰符 signed、unsigned、long 和 short 可应用于整型,signedunsigned 可应用于字符型,long 可应用于双精度型。

修饰符 signedunsigned 也可以作为 longshort 修饰符的前缀。例如:unsigned long int

C++ 允许使用速记符号来声明无符号短整数无符号长整数。您可以不写 int,只写单词 unsigned shortunsigned long,int 是隐含的。例如,下面的两个语句都声明了无符号整型变量。

unsigned x;
unsigned int y;

C++ 中的类型限定符

类型限定符提供了变量的额外信息。

限定符含义
constconst 类型的对象在程序执行期间不能被修改改变。
volatile修饰符 volatile 告诉编译器,变量的值可能以程序未明确指定的方式被改变。
restrictrestrict 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 restrict。

C++ 存储类

存储类定义 C++ 程序中变量/函数的范围(可见性)生命周期。这些说明符放置在它们所修饰的类型之前。

下面列出 C++ 程序中可用的存储类:

  • auto
  • register
  • static
  • extern
  • mutable

auto 存储类

auto 存储类是所有局部变量默认的存储类。

{
   int mount;
   auto int month;
}

上面的实例定义了两个带有相同存储类的变量,auto 只能用在函数内,即 auto 只能修饰局部变量

register 存储类

register 存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的 ‘&’ 运算符(因为它没有内存位置)。

{
   register int miles;
}

寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,定义 ‘register’ 并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。

static 存储类

static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。

static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内

在 C++ 中,当 static 用在类数据成员上时,会导致仅有一个该成员的副本被类的所有对象共享

extern 存储类

extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 extern 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。

extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候,当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。

mutable 存储类

mutable 说明符仅适用于类的对象,它允许对象的成员替代常量。也就是说,mutable 成员可以通过 const 成员函数修改。

C++ 函数

函数是一组一起执行一个任务的语句。每个 C++ 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。

您可以把代码划分到不同的函数中。如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根据每个函数执行一个特定的任务来进行的。

函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。

定义函数

在 C++ 中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:

  • **返回类型:**一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void
  • **函数名称:**这是函数的实际名称。函数名和参数列表一起构成了函数签名。
  • **参数:**参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
  • **函数主体:**函数主体包含一组定义函数执行任务的语句。

函数声明

函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。

在函数声明中,参数的名称并不重要,只有参数的类型是必需的。

函数参数

如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数

形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。

调用类型描述
传值调用该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数对实际参数没有影响。
指针调用该方法把参数的地址复制给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
引用调用该方法把参数的引用复制给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。

默认情况下,C++ 使用传值调用来传递参数。一般来说,这意味着函数内的代码不能改变用于调用函数的参数。

C++数组

数组可以存储一个固定大小的相同类型元素的顺序集合。

所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。

声明数组

在 C++ 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:

type arrayName [ arraySize ];

这叫做一维数组。arraySize 必须是一个大于零的整数常量,type 可以是任意有效的 C++ 数据类型。

多维数组

多维数组声明的一般形式如下:

type name[size1][size2]...[sizeN];

数组指针

数组名是一个指向数组中第一个元素的常量指针。因此,在下面的声明中:

double balance[50];

balance 是一个指向 &balance[0] 的指针,即数组 balance 的第一个元素的地址。

p 赋值为 balance 的第一个元素的地址:

double *p;
double balance[10];
p = balance;

使用数组名作为常量指针是合法的,反之亦然。因此,*(balance + 4) 是一种访问 balance[4] 数据的合法方式。

一旦您把第一个元素的地址存储在 p 中,您就可以使用 *p*(p+1)*(p+2) 等来访问数组元素。

#include <iostream>
using namespace std;
 
int main ()
{
   // 带有 5 个元素的整型数组
   double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
   double *p;

   p = balance;
 
   // 输出数组中每个元素的值
   cout << "使用指针的数组值 " << endl; 
   for ( int i = 0; i < 5; i++ )
   {
       cout << "*(p + " << i << ") : ";
       cout << *(p + i) << endl;
   }

   cout << "使用 balance 作为地址的数组值 " << endl;
   for ( int i = 0; i < 5; i++ )
   {
       cout << "*(balance + " << i << ") : ";
       cout << *(balance + i) << endl;
   }
 
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

使用指针的数组值
*(p + 0) : 1000
*(p + 1) : 2
*(p + 2) : 3.4
*(p + 3) : 17
*(p + 4) : 50
使用 balance 作为地址的数组值
*(balance + 0) : 1000
*(balance + 1) : 2
*(balance + 2) : 3.4
*(balance + 3) : 17
*(balance + 4) : 50

在上面的实例中,p 是一个指向 double 型的指针,这意味着它可以存储一个 double 类型的变量。一旦我们有了 p 中的地址,*p 将给出存储在 p 中相应地址的值。

传递数组给函数

C++ 不允许向函数传递一个完整的数组作为参数,但是,您可以通过指定不带索引的数组名来传递一个指向数组的指针。

如果您想要在函数中传递一个一维数组作为参数,您必须以下面三种方式来声明函数形式参数,这三种声明方式的结果是一样的,因为每种方式都会告诉编译器将要接收一个整型指针。同样地,您也可以传递一个多维数组作为形式参数。

方式 1

形式参数是一个指针:

void myFunction(int *param)
{
}

方式 2

形式参数是一个已定义大小的数组:

void myFunction(int param[10])
{
}

方式 3

形式参数是一个未定义大小的数组:

void myFunction(int param[])
{
}

就函数而言,数组的长度是无关紧要的,因为 C++ 不会对形式参数执行边界检查。

C++指针

每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。

声明指针

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。

type *var-name;

在这里,type 是指针的基类型,它必须是一个有效的 C++ 数据类型,var-name 是指针变量的名称。用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针。以下是有效的指针声明:

int    *ip;    /* 一个整型的指针 */
double *dp;    /* 一个 double 型的指针 */
float  *fp;    /* 一个浮点型的指针 */
char   *ch     /* 一个字符型的指针 */

所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同

使用指针

使用指针时会频繁进行以下几个操作:

  1. 定义一个指针变量
  2. 把变量地址赋值给指针
  3. 访问指针变量中可用地址的值

可以通过使用一元运算符 ***** 来返回位于操作数所指定地址的变量的值。

#include <iostream>

using namespace std;

int main ()
{
   int  var = 20;   // 实际变量的声明
   int  *ip;        // 指针变量的声明

   ip = &var;       // 在指针变量中存储 var 的地址

   cout << "Value of var variable: ";
   cout << var << endl;

   // 输出在指针变量中存储的地址
   cout << "Address stored in ip variable: ";
   cout << ip << endl;

   // 访问指针中地址的值
   cout << "Value of *ip variable: ";
   cout << *ip << endl;

   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Value of var variable: 20
Address stored in ip variable: 0xbfc601ac
Value of *ip variable: 20

NULL指针

NULL 指针是一个定义在标准库中的值为零的常量。

在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。

赋为 NULL 值的指针被称为空指针

#include <iostream>
using namespace std;
int main ()
{
   int  *ptr = NULL;
   cout << "ptr 的值是 " << ptr ;
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

ptr 的值是 0

在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。

如需检查一个空指针,可以使用 if 语句,如下所示:

if(ptr)     /* 如果 p 非空,则完成 */
if(!ptr)    /* 如果 p 为空,则完成 */

因此,如果所有未使用的指针都被赋予空值,同时避免使用空指针,就可以防止误用一个未初始化的指针。

很多时候,未初始化的变量存有一些垃圾值,导致程序难以调试。

指针的算术运算

可以对指针进行四种算术运算:++、–、+、-。

假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:

ptr++

在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 个字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。

递增一个指针

我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,因为数组是一个常量指针。

下面的程序递增变量指针,以便顺序访问数组中的每一个元素:

#include <iostream>

using namespace std;
const int MAX = 3;

int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;

   // 指针中的数组地址
   ptr = var;
   for (int i = 0; i < MAX; i++)
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;

      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;

      // 移动到下一个位置
      ptr++;
   }
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Address of var[0] = 0xbfa088b0
Value of var[0] = 10
Address of var[1] = 0xbfa088b4
Value of var[1] = 100
Address of var[2] = 0xbfa088b8
Value of var[2] = 200

递减一个指针

同样地,对指针进行递减运算,即把值减去其数据类型的字节数,如下所示:

#include <iostream>

using namespace std;
const int MAX = 3;

int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;

   // 指针中最后一个元素的地址
   ptr = &var[MAX-1];
   for (int i = MAX; i > 0; i--)
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;

      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;

      // 移动到下一个位置
      ptr--;
   }
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Address of var[3] = 0xbfdb70f8
Value of var[3] = 200
Address of var[2] = 0xbfdb70f4
Value of var[2] = 100
Address of var[1] = 0xbfdb70f0
Value of var[1] = 10

指针的比较

指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。

#include <iostream>

using namespace std;
const int MAX = 3;

int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;

   // 指针中第一个元素的地址
   ptr = var;
   int i = 0;
   // 只要变量指针所指向的地址小于或等于数组的最后一个元素的地址 &var[MAX - 1],则把变量指针进行递增
   while ( ptr <= &var[MAX - 1] )
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;

      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;

      // 指向上一个位置
      ptr++;
      i++;
   }
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Address of var[0] = 0xbfce42d0
Value of var[0] = 10
Address of var[1] = 0xbfce42d4
Value of var[1] = 100
Address of var[2] = 0xbfce42d8
Value of var[2] = 200

指针数组

下面是一个指向整数的指针数组的声明:

int *ptr[MAX];

在这里,把 ptr 声明为一个数组,由 MAX 个整数指针组成。因此,ptr 中的每个元素,都是一个指向 int 值的指针。下面的实例用到了三个整数,它们将存储在一个指针数组中,如下所示:

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
   int *ptr[MAX];
 
   for (int i = 0; i < MAX; i++)
   {
      ptr[i] = &var[i]; // 赋值为整数的地址
   }
   for (int i = 0; i < MAX; i++)
   {
      cout << "Value of var[" << i << "] = ";
      cout << *ptr[i] << endl;
   }
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200

您也可以用一个指向字符的指针数组来存储一个字符串列表,如下:

#include <iostream>
 
using namespace std;
const int MAX = 4;
 
int main ()
{
 const char *names[MAX] = {
                   "Zara Ali",
                   "Hina Ali",
                   "Nuha Ali",
                   "Sara Ali",
   };

   for (int i = 0; i < MAX; i++)
   {
      cout << "Value of names[" << i << "] = ";
      cout << names[i] << endl;
   }
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali

指向指针的指针(多级间接寻址)

指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。

通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。

C++ 指向指针的指针

一个指向指针的指针变量必须如下声明,即在变量名前放置两个星号。例如,下面声明了一个指向 int 类型指针的指针:

int **var;

当一个目标值被一个指针间接指向到另一个指针时,访问这个值需要使用两个星号运算符,如下面实例所示:

#include <iostream>
 
using namespace std;
 
int main ()
{
   int  var;
   int  *ptr;
   int  **pptr;

   var = 3000;

   // 获取 var 的地址
   ptr = &var;

   // 使用运算符 & 获取 ptr 的地址
   pptr = &ptr;

   // 使用 pptr 获取值
   cout << "Value of var :" << var << endl;
   cout << "Value available at *ptr :" << *ptr << endl;
   cout << "Value available at **pptr :" << **pptr << endl;

   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Value of var = 3000
Value available at *ptr = 3000
Value available at **pptr = 3000

传递指针给函数

C++ 允许您传递指针给函数,只需要简单地声明函数参数为指针类型即可。

下面的实例中,我们传递一个无符号的 long 型指针给函数,并在函数内改变这个值:

#include <iostream>
#include <ctime>
 
using namespace std;
void getSeconds(unsigned long *par);

int main ()
{
   unsigned long sec;

   getSeconds( &sec );

   // 输出实际值
   cout << "Number of seconds :" << sec << endl;

   return 0;
}

void getSeconds(unsigned long *par)
{
   // 获取当前的秒数
   *par = time( NULL );
   return;
}

当上面的代码被编译和执行时,它会产生下列结果:

Number of seconds :1294450468

能接受指针作为参数的函数,也能接受数组作为参数,如下所示:

#include <iostream>
using namespace std;

// 函数声明
double getAverage(int *arr, int size);

int main ()
{
    // 带有 5 个元素的整型数组
    int balance[5] = {1000, 2, 3, 17, 50};
    double avg;

    // 传递一个指向数组的指针作为参数
    avg = getAverage( balance, 5 ) ;

    // 输出返回值
    cout << "Average value is: " << avg << endl; 

    return 0;
}

double getAverage(int *arr, int size)
{
    int i, sum = 0;       
    double avg;          

    for (i = 0; i < size; ++i)
    {
        sum += arr[i];
    }

    avg = double(sum) / size;

    return avg;
}

当上面的代码被编译和执行时,它会产生下列结果:

Average value is: 214.4

从函数返回指针

声明一个返回指针的函数,如下所示:

int * myFunction()
{
}

另外,C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。

现在,让我们来看下面的函数,它会生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下:

#include <iostream>
#include <ctime>

using namespace std;

// 要生成和返回随机数的函数
int * getRandom( )
{
    static int r[10];

    // 设置种子
    srand( (unsigned)time( NULL ) );
    for (int i = 0; i < 10; ++i)
    {
        r[i] = rand();
        cout << r[i] << endl;
    }

    return r;
}

// 要调用上面定义函数的主函数
int main ()
{
    // 一个指向整数的指针
    int *p;

    p = getRandom();
    for ( int i = 0; i < 10; i++ )
    {
        cout << "*(p + " << i << ") : ";
        cout << *(p + i) << endl;
    }

    return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

624723190
1468735695
807113585
976495677
613357504
1377296355
1530315259
1778906708
1820354158
667126415
*(p + 0) : 624723190
*(p + 1) : 1468735695
*(p + 2) : 807113585
*(p + 3) : 976495677
*(p + 4) : 613357504
*(p + 5) : 1377296355
*(p + 6) : 1530315259
*(p + 7) : 1778906708
*(p + 8) : 1820354158
*(p + 9) : 667126415

C++ 指针 vs 数组

指针和数组是密切相关的。事实上,指针和数组在很多情况下是可以互换的。例如,一个指向数组开头的指针,可以通过使用指针的算术运算或数组索引来访问数组。

然而,指针和数组并不是完全互换的。例如,请看下面的程序:

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
 
   for (int i = 0; i < MAX; i++)
   {
      *var = i;    // 这是正确的语法
      var++;       // 这是不正确的
   }
   return 0;
}

把指针运算符 * 应用到 var 上是完全可以接受的,但修改 var 的值是非法的。这是因为 var 是一个指向数组开头的常量,不能作为左值。

由于一个数组名对应一个指针常量,只要不改变数组的值,仍然可以用指针形式的表达式。例如,下面是一个有效的语句,把 var[2] 赋值为 500:

*(var + 2) = 500;

上面的语句是有效的,且能成功编译,因为 var 未改变。

C++ 引用

引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。

创建引用

试想变量名称是变量附属在内存位置中的标签,您可以把引用当成是变量附属在内存位置中的第二个标签。因此,您可以通过原始变量名称或引用来访问变量的内容。例如:

int i = 17;

我们可以为 i 声明引用变量,如下所示:

int& r = i;

在这些声明中,& 读作引用。引用通常用于函数参数列表和函数返回值。

#include <iostream>
 
using namespace std;
 
int main ()
{
   // 声明简单的变量
   int    i;
   double d;
 
   // 声明引用变量
   int&    r = i;	//r 是一个初始化为 i 的整型引用
   double& s = d;	//s 是一个初始化为 d 的 double 型引用
   
   i = 5;
   cout << "Value of i : " << i << endl;
   cout << "Value of i reference : " << r  << endl;
 
   d = 11.7;
   cout << "Value of d : " << d << endl;
   cout << "Value of d reference : " << s  << endl;
   
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Value of i : 5
Value of i reference : 5
Value of d : 11.7
Value of d reference : 11.7

把引用作为参数

#include <iostream>
using namespace std;
 
// 函数声明
void swap(int& x, int& y);
 
int main ()
{
   // 局部变量声明
   int a = 100;
   int b = 200;
 
   cout << "交换前,a 的值:" << a << endl;
   cout << "交换前,b 的值:" << b << endl;
 
   /* 调用函数来交换值 */
   swap(a, b);
 
   cout << "交换后,a 的值:" << a << endl;
   cout << "交换前,b 的值:" << b << endl;
 
   return 0;
}
 
// 函数定义
void swap(int& x, int& y)
{
   int temp;
   temp = x; /* 保存地址 x 的值 */
   x = y;    /* 把 y 赋值给 x */
   y = temp; /* 把 x 赋值给 y  */
  
   return;
}

当上面的代码被编译和执行时,它会产生下列结果:

交换前,a 的值: 100
交换前,b 的值: 200
交换后,a 的值: 200
交换后,b 的值: 100

把引用作为返回值

通过使用引用来替代指针,会使 C++ 程序更容易阅读和维护。C++ 函数可以返回一个引用,方式与返回一个指针类似。

当函数返回一个引用时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边。

#include <iostream>
#include <ctime>

using namespace std;

double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};

double& setValues( int i )
{
    return vals[i];   // 返回第 i 个元素的引用
}

// 要调用上面定义函数的主函数
int main ()
{
    cout << "改变前的值" << endl;
    for ( int i = 0; i < 5; i++ )
    {
        cout << "vals[" << i << "] = ";
        cout << vals[i] << endl;
    }

    setValues(1) = 20.23; // 改变第 2 个元素
    setValues(3) = 70.8;  // 改变第 4 个元素

    cout << "改变后的值" << endl;
    for ( int i = 0; i < 5; i++ )
    {
        cout << "vals[" << i << "] = ";
        cout << vals[i] << endl;
    }
    return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

改变前的值
vals[0] = 10.1
vals[1] = 12.6
vals[2] = 33.1
vals[3] = 24.1
vals[4] = 50
改变后的值
vals[0] = 10.1
vals[1] = 20.23
vals[2] = 33.1
vals[3] = 70.8
vals[4] = 50

当返回一个引用时,要注意被引用的对象不能超出作用域。所以返回一个对局部变量的引用是不合法的,但是,可以返回一个对静态变量的引用。

int& func() {
   int q;
   //! return q; // 在编译时发生错误
   static int x;
   return x;     // 安全,x 在函数作用域外依然是有效的
}

C++ 引用 vs 指针

引用很容易与指针混淆,它们之间有三个主要的不同:

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。

C++ 基本的输入输出

C++ 的 I/O 发生在流中,流是字节序列。

  • 如果字节流是从设备(如键盘、磁盘驱动器、网络连接等)流向内存,这叫做输入操作

  • 如果字节流是从内存流向设备(如显示屏、打印机、磁盘驱动器、网络连接等),这叫做输出操作

I/O 库头文件

下列的头文件在 C++ 编程中很重要。

头文件函数和描述
<iostream>该文件定义了 cin、cout、cerrclog 对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。
<iomanip>该文件通过所谓的参数化的流操纵器(比如 setwsetprecision),来声明对执行标准化 I/O 有用的服务。
<fstream>该文件为用户控制的文件处理声明服务。

标准输出流(cout)

预定义的对象 coutostream 类的一个实例。cout 对象"连接"到标准输出设备,通常是显示屏。cout 是与流插入运算符 << 结合使用的。

C++ 编译器根据要输出变量的数据类型,选择合适的流插入运算符来显示值。<< 运算符被重载来输出内置类型(整型、浮点型、double 型、字符串和指针)的数据项。

流插入运算符 << 在一个语句中可以多次使用。

标准输入流(cin)

预定义的对象 cinistream 类的一个实例。cin 对象附属到标准输入设备,通常是键盘。cin 是与流提取运算符 >> 结合使用的。

C++ 编译器根据要输入值的数据类型,选择合适的流提取运算符来提取值,并把它存储在给定的变量中。

流提取运算符 >> 在一个语句中可以多次使用。

标准错误流(cerr)

预定义的对象 cerrostream 类的一个实例。cerr 对象附属到标准错误设备,通常也是显示屏,但是 cerr 对象是非缓冲的,且每个流插入到 cerr 都会立即输出。

cerr 也是与流插入运算符 << 结合使用的。

标准日志流(clog)

预定义的对象 clogostream 类的一个实例。clog 对象附属到标准错误设备,通常也是显示屏,但是 clog 对象是缓冲的。这意味着每个流插入到 clog 都会先存储在缓冲区中,直到缓冲填满或者缓冲区刷新时才会输出。

clog 也是与流插入运算符 << 结合使用的。

C++结构体

C/C++ 数组允许定义可存储相同类型数据项的变量,但是结构是 C++ 中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。

定义结构

为了定义结构,您必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:

struct [structure tag]
{
   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];  

structure tag 是可选的,每个 member definition 是标准的变量定义,比如 int i; 或者 float f; 或者其他有效的变量定义。在结构定义的末尾,最后一个分号之前,您可以指定一个或多个结构变量,这是可选的。

structure tag 是可选的,每个 member definition 是标准的变量定义,比如 int i; 或者 float f; 或者其他有效的变量定义。在结构定义的末尾,最后一个分号之前,您可以指定一个或多个结构变量,这是可选的。下面是声明 Book 结构的方式:

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
}book;  

访问结构成员

为了访问结构的成员,我们使用成员访问运算符(.)

#include <iostream>
#include <cstring>
 
using namespace std;
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( )
{
   struct Books Book1;        // 声明 Book1,类型为 Book
   struct Books Book2;        // 声明 Book2,类型为 Book
 
   // Book1 详述
   strcpy( Book1.title, "Learn C++ Programming");
   strcpy( Book1.author, "Chand Miyan"); 
   strcpy( Book1.subject, "C++ Programming");
   Book1.book_id = 6495407;

   // Book2 详述
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Yakit Singha");
   strcpy( Book2.subject, "Telecom");
   Book2.book_id = 6495700;
 
   // 输出 Book1 信息
   cout << "Book 1 title : " << Book1.title <<endl;
   cout << "Book 1 author : " << Book1.author <<endl;
   cout << "Book 1 subject : " << Book1.subject <<endl;
   cout << "Book 1 id : " << Book1.book_id <<endl;

   // 输出 Book2 信息
   cout << "Book 2 title : " << Book2.title <<endl;
   cout << "Book 2 author : " << Book2.author <<endl;
   cout << "Book 2 subject : " << Book2.subject <<endl;
   cout << "Book 2 id : " << Book2.book_id <<endl;

   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Book 1 title : Learn C++ Programming
Book 1 author : Chand Miyan
Book 1 subject : C++ Programming
Book 1 id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Yakit Singha
Book 2 subject : Telecom
Book 2 id : 6495700

结构作为函数参数

您可以把结构作为函数参数,传参方式与其他类型的变量或指针类似。

#include <iostream>
#include <cstring>
 
using namespace std;
void printBook( struct Books book );

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( )
{
   struct Books Book1;        // 声明 Book1,类型为 Book
   struct Books Book2;        // 声明 Book2,类型为 Book
 
   // Book1 详述
   strcpy( Book1.title, "Learn C++ Programming");
   strcpy( Book1.author, "Chand Miyan"); 
   strcpy( Book1.subject, "C++ Programming");
   Book1.book_id = 6495407;

   // Book2 详述
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Yakit Singha");
   strcpy( Book2.subject, "Telecom");
   Book2.book_id = 6495700;
 
   // 输出 Book1 信息
   printBook( Book1 );

   // 输出 Book2 信息
   printBook( Book2 );

   return 0;
}
void printBook( struct Books book )
{
   cout << "Book title : " << book.title <<endl;
   cout << "Book author : " << book.author <<endl;
   cout << "Book subject : " << book.subject <<endl;
   cout << "Book id : " << book.book_id <<endl;
}

当上面的代码被编译和执行时,它会产生下列结果:

Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700

指向结构的指针

您可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似,如下所示:

struct Books *struct_pointer;

现在,您可以在上述定义的指针变量中存储结构变量的地址。为了查找结构变量的地址,请把 & 运算符放在结构名称的前面,如下所示:

struct_pointer = &Book1;

为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符,如下所示:

struct_pointer->title;

让我们使用结构指针来重写上面的实例,这将有助于您理解结构指针的概念:

struct_pointer->title;

让我们使用结构指针来重写上面的实例,这将有助于您理解结构指针的概念:

#include <iostream>
#include <cstring>
 
using namespace std;
void printBook( struct Books *book );

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( )
{
   struct Books Book1;        // 声明 Book1,类型为 Book
   struct Books Book2;        // 声明 Book2,类型为 Book */
 
   // Book1 详述
   strcpy( Book1.title, "Learn C++ Programming");
   strcpy( Book1.author, "Chand Miyan"); 
   strcpy( Book1.subject, "C++ Programming");
   Book1.book_id = 6495407;

   // Book2 详述
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Yakit Singha");
   strcpy( Book2.subject, "Telecom");
   Book2.book_id = 6495700;
 
   // 通过传 Book1 的地址来输出 Book1 信息
   printBook( &Book1 );

   // 通过传 Book2 的地址来输出 Book2 信息
   printBook( &Book2 );

   return 0;
}
// 该函数以结构指针作为参数
void printBook( struct Books *book )
{
   cout << "Book title : " << book->title <<endl;
   cout << "Book author : " << book->author <<endl;
   cout << "Book subject : " << book->subject <<endl;
   cout << "Book id : " << book->book_id <<endl;
} 

当上面的代码被编译和执行时,它会产生下列结果:

Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700

typedef 关键字

下面是一种更简单的定义结构的方式,您可以为创建的类型取一个"别名"。例如:

typedef struct
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
}Books;

现在,您可以直接使用 Books 来定义 Books 类型的变量,而不需要使用 struct 关键字。下面是实例:

Books Book1, Book2;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++面向过程 的相关文章

  • django JWT 验证401错误

    因为前端请求时携带了Authorization请求头 xff08 主要是JWT xff09 xff0c 而如果用户未登录 xff0c 此请求头的JWT无意义 xff08 没有值 xff09 xff0c 为了防止REST framework框
  • “轻松搞定 CMake”系列之 find_package 用法详解

    一 find packakge 命令基本介绍 在我们实际开发过程中 xff0c 经常不可避免会使用到第三方开源库 xff0c 这些开源库可能是通过 apt get install 命令自动安装到系统目录中 xff0c 也可能是由我们自己下载
  • STL中的string类

    一 string是什么 xff1f string类是专门的字符串操作的一个类 xff0c 非常的强大 二 string与char 的区别 xff1a char 呢就是指向字符数组地址的指针 xff0c 然后我们提供了一个string h x
  • Cpp 对象模型探索 / 父类和子类调用构造函数和析构函数的顺序

    2018 03 19 创建人 xff1a Ruo Xiao 邮箱 xff1a xclsoftware 64 163 com 一 建立对象过程 father son 栗子 xff1a span class token keyword clas
  • 串口通信 / 奇校验、偶校验、0 校验和 1 校验

    时间 xff1a 2019 01 28 创建人 xff1a Ruo Xiao 邮箱 xff1a xclsoftware 64 163 com 一 目的 对数据传输的正确与否进行校验 二 方法 奇校验 xff1a 让主体数据加上校验位中的 1
  • 堆栈向下增长和向上增长的理解

    时间 xff1a 2019 01 31 创建人 xff1a Ruo Xiao 邮箱 xff1a xclsoftware 64 163 com 假设堆栈为数组Taskstk unsigned int Taskstk 255 堆栈压数从栈顶压向
  • C++--名字修饰

    名字修饰 在C C 43 43 中 xff0c 一个程序要运行起来 xff0c 需要经历以下几个阶段 xff1a 预处理 编译 汇编 链接 名字修饰 xff08 Name Mangling xff09 是一种在编译过程中 xff0c 将函数
  • 【ROS入门】解决Could not find a package configuration file provided by “nmea_msgs“问题

    笔者Linux虚拟机系统为Ubuntu20 04 xff0c 安装ROS我参考的是https blog csdn net weixin 45168199 article details 106910446 安装完成后创建ROS工作空间 mk
  • C#中的屏蔽、覆写和抽象

    屏蔽基类成员 虽然派生类不能删除其继承的任何成员 xff0c 但可以声明一个与基类成员签名相同的成员来屏蔽之 xff08 注意方法的签名由名称和参数列表组成 xff0c 不包括返回值类型 xff09 要让编译器知道你在故意屏蔽继承的成员 x
  • 【计算机网络】第一章:计算机网络概述

    各个章节的知识点总结传送门如下 xff0c 欢迎自取 xff1a 计算机网络 第一章 xff1a 计算机网络概述描述 计算机网络 第二章 xff1a 物理层 计算机网络 第三章 xff1a 数据链路层 计算机网络 第四章 xff1a 网络层
  • 【计算机网络】第二章:物理层

    各个章节的知识点总结传送门如下 xff0c 欢迎自取 xff1a 计算机网络 第一章 xff1a 计算机网络概述https blog csdn net iwanderu article details 103795715 计算机网络 第二章
  • 【计算机网络】第四章:网络层

    各个章节的知识点总结传送门如下 xff0c 欢迎自取 xff1a 计算机网络 第一章 xff1a 计算机网络概述https blog csdn net iwanderu article details 103795715 计算机网络 第二章
  • ASCII码与16进制的互相转换(表)

    所谓的ASCII和16进制都只是概念上的东西 xff0c 在计算机中通通是二进制 转换应该是输出的转换 xff0c 同样是一个数 xff0c 在计算机内存中表示是一样的 xff0c 只是输出不一样 ASCII是针对字符的编码 xff0c 几
  • 【操作系统】 Operation System 第一章:概述

    各部分总结知识点如下 xff1a 操作系统 Operation System 第一章 xff1a 概述 操作系统 Operation System 第二章 xff1a 操作系统基础操作 操作系统 Operation System 第三章 x
  • 【openCV踩坑日记】人工数据集Synthetic Shapes dataset的生成方法

    1 为什么要介绍这个方法 xff1f 2018年的时候 xff0c D DeTone等人发表了Self Supervised Interest Point Detection and Description xff0c 提出了一种特征提取S
  • 【SLAM】ORB-SLAM3解析——综述(1)

    之前学习VINS和LIO SAM的时候都是代码流 xff0c 不是很重视看论文 xff0c 现在有空学ORB SLAM3了 xff0c 这一次 xff0c 先看一下论文 考虑到边上班边学 xff0c 更新的会比较慢 看完论文之后 xff0c
  • 【SLAM】LVI-SAM解析——综述

    LVI SAM可以认为是LIO SAM和VINS MONO的合体 xff0c 在此基础上的修改不大 github xff1a https github com TixiaoShan LVI SAM paper LVI SAM Tightly

随机推荐

  • 【SLAM】DM-VIO(ros版)安装和论文解读

    1 dm vio的安装 进入官方链接 xff0c 基本上就是按照readme的操作来 xff1a 下载代码 xff1a git clone https github com lukasvst dm vio git 安装gtsam xff1a
  • 【SLAM】SVO2.0编译运行和论文代码解读

    SVO2是我遇到的最难编译的代码了 xff0c 毕竟公开版本怎么能放最好的代码呢 xff0c 搞了快一个星期 xff0c 终于跑起来了 github xff1a GitHub uzh rpg rpg svo pro open 论文 xff1
  • 【工具篇】postman的完全使用,全是干货

    目录 一 x1f347 GET请求 二 x1f348 POST请求 三 x1f349 PUT请求 四 x1f34a DELETE请求 五 x1f34b Headers 六 x1f34c 认证 xff08 1 xff09 基本认证 xff1a
  • GPS全球定位系统构成及原理

    GPS全球定位系统构成及原理 全球定位系统 GPS 是本世纪70年代由美国陆海空三军联合研制的新一代空间卫星导航定位系统 其主要目的是为陆 海 空三大领域提供实时 全天候和全球性的导航服务 xff0c 并用于情报收集 核爆监测和应急通讯等一
  • Visual C++设计UDP协议通讯示例

    下载本文源代码 一 绪言 UDP是一种面向非连接 xff0c 不可靠的通讯协议 xff0c 相对于 TCP来说 xff0c 虽然可靠性不及 xff0c 但传输效率较高 所以在网络上仍有很大的用途 这几日需要了解下udp通讯的过程 xff0c
  • 树莓派控制舵机云台

    文章目录 学习记录舵机代码分析 学习记录 手上有一套电赛时候买的舵机云台 扭矩15KG 型号为LD 1501MG 舵机 两个LD 1501MG舵机角度范围都是180度 控制的PWM波周期为20ms 角度与正脉冲宽度映射如下所示 0 5ms
  • jetson nano 编译pyrealsense2 运行t265

    在win10 的环境下 xff0c 安装pyrealsense2 xff0c 只需要简单的pip就可以了 xff0c 没想到在jetson nano下却花了那么多时间和精力 其实解决方案网上都有 xff0c 但是比较零碎 xff0c 只能遇
  • openmv探索_4_AprilTag标记追踪

    原理及代码 AprilTag标记追踪 空间坐标系的建立 以镜头中心为坐标系原点 xff0c 建立空间坐标系 图2 1 空间坐标系 旋转角度 xff08 参考系是上图中的坐标系 xff09 1 初始状态 图3 1 物体摆放的初始位置 上图的
  • Xsens MTi传感器 ROS下配置

    Xsens MTi传感器 ROS 1 概述2 MTI设置 MTmanager3 ROS下信息发布 MTSDK4 找不到设备 xff15 参考链接 xff16 延伸阅读传感器配置节点程序分析经典SLAM 1 概述 主要介绍Ubuntu下对Xs
  • 雷达点云 PointCloud2 格式转换

    雷达点云 sensor msgs PointCloud2 pcl PointCloud 数据格式转换参考代码 官方对点云格式的介绍 xff0c 主要有四种 xff0c sensor msgs PointCloud已经弃用 参考 sensor
  • Gmapping 之安装与配置

    Gmapping 之安装与配置 1 概述2 安装2 1 github仓库 3 运行3 1 运行截图3 2 重采样时的提示信息3 3 tf树 96 rosrun rqt tf tree rqt tf tree 96 3 4 所有的坐标变换信息
  • Gmapping Dropped 100.00% of messages so far 解决办法

    Dropped 100 00 of messages so far解决办法 概述显示tf树正常情况报错情况参考链接Gmapping 概述 运行Gmappping时出现错误提示 xff0c 其他参数 xff1a 话题等都设置正确了 xff0c
  • LOAM SLAM安装与配置

    LOAM SLAM安装与配置 1 概述2 安装3 运行4 结果5 其他6 参考链接 1 概述 简单介绍LOAM SLAM的安装与配置 xff0c 希望能帮助大家 xff0c 同时供自己以后参考 2 安装 运行LOAM需要PCL等库支持 xf
  • 什么是MSB、LSB,什么是大端、小端,区别是什么?

    MSB是Most Significant Bit的缩写 xff0c 最高有效位 在二进制数中 xff0c MSB是最高加权位 与十进制数字中最左边的一位类似 通常 xff0c MSB位于二进制数的最左侧 xff0c LSB位于二进制数的最右
  • ROS报错 cant locate node 解决办法

    ROS报错 can 39 t locate node 解决办法 1 概述2 原因3 解决办法4 其他 1 概述 ROS突然出现不能运行节点的问题 xff0c 这里简单介绍一下自己的解决办法 这个方法还是有缺陷 xff0c 更新方法在ROS编
  • ubuntu 开机后 按键 鼠标不能用

    ubuntu 开机后 按键 鼠标不能用 1 现象2 解决办法3 参考链接 1 现象 版本ubuntu 1804安装bumblebee后 xff0c 重启机器出现不能使用鼠标 键盘的现象 xff0c 具体点就是 xff0c 只有开机后的桌面显
  • 相机标定之使用ROS节点程序

    相机标定之使用ROS节点程序 1 概述2 准备3 步骤4 相关链接 1 概述 简单介绍如何使用ROS节点程序进行针孔模型相机标定的步骤 xff0c 供自己以后参考 xff0c 同时希望给大家带来帮助 2 准备 提前准备好棋盘格并打印出来 x
  • 相机标定之使用Matlab工具箱

    相机标定之使用Matlab工具箱 1 概述2 准备3 步骤4 相关链接 1 概述 简单介绍如何使用Matlab进行针孔模型相机标定的步骤 xff0c 供自己以后参考 xff0c 同时希望给大家带来帮助 2 准备 提前准备好棋盘格并打印出来
  • QT安装教程

    QT安装教程 1 概述2 下载安装2 1 下载2 2 安装2 3 安装配置其他环境2 4 安装成功2 5 问题及解决 3 参考链接 1 概述 简单介绍如何在Ubuntu下安装QT xff0c 希望能够帮助大家 xff0c 同时给自己一个参考
  • C++面向过程

    参考文档 xff1a C 43 43 教程 C 43 43 简介 概述 C 43 43 是一种静态类型的 编译式的 通用的 大小写敏感的 不规则的编程语言 xff0c 支持过程化编程 面向对象编程和泛型编程 C 43 43 是 C 的一个超