cpp-变量

1.枚举类型

枚举类型是用户自定义的类型,在定义时要列举出该枚举类型所有的数值。

枚举的定义

定义格式如下:

[enum] enumName {val1, val2, val3}

  • 其中的通常为较易懂的字符,这也是枚举类型的使用目的:增强易读性
  • 按照顺序,枚举值依次与1,2,3等整数一一对应。在定义时也可以指出枚举值对应的数值,只是要指出的需要在左边,剩下未指出的的将会按照递增顺序。如:enum Day {sun = 7, mon = 1, tue = 2, wed, thu, fri, sat}

对枚举类型的操作

  1. 枚举类型与整数值一一对应,所以可以进行计算。
    1. 可以把枚举量赋值给整型变量;整型变量通过强制类型转换可以赋值给(在其值范围内的)枚举变量
    2. 枚举变量可以进行大小比较
  2. 对枚举变量的输出结果是其对应的整数值

2.数组

数组是一组组成元素类型相同的,在内存存储连续的序列。

数组的定义

一维数组的定义

dataType arrayName[memNum]

typedef在用于数组定义时有种特殊的写法:typedef int A[10];。这种写法将int [10]这样的数组定义作了A,其特殊之处在于新的名字夹在组成类型的中间

初始化表

指在定义数组时,同时给出其值的表,格式为:int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

  • 若使用初始化表而没有给出初值/给出的初值不够,则会用0作为其默认值进行补全
  • 使用初始化表且完整给出所有值则可以省略数组定义时的个数:int a[] = {1, 2, 3, 4, 5}

字符串数组

字符串数组是指形如char s[num]的数组。

所有的字符串数组在计算长度时都需要-1,因为要在末尾添加字符串的结束标志\0(新标准下数组长度似乎不再需要为结束标志留位置,且定义时给出的num下标即为最大可访问的下标)。在输出时会检测这个\0作为结束标志,而不会将这个标志输出,这种字符串叫asciiz串

字符串数组的初始化

字符串数组可以用如下的方式进行初始化:

  • char s[] = {"hello"};
  • char s[] = {'h', 'e', 'l', 'l', 'o'};
  • char s[] = "hello"

这些方式都会在其末尾加上\0,而不需要考虑太多。若要求用户在运行时为字符串赋值,则要特别注意在用户输入后向末端添加\0

二维数组

二维数组的定义

格式:dataType arrayName[index1][index2];,其中的index1对应行,index2对应列,可访问下标范围为0-index1 - 1, 0-index2 - 1

  • 使用typedef来简化:typedef int nickName[index1][index2];

  • 可以用初始化表来为二维数组定义

    • int a [2][3] = {{2, 3}, {3, 4}}:这样初始化后的二维数组对应为2, 3, 0; 3, 4, 0,即是说可以用大括号内嵌套大括号的方式指定

二维数组的使用

  • 在定义函数时若涉及二维数组的调用,则必须指明列数;行数可以通过用户传入的参数来界定,以此获得较灵活的使用。如:
    • int max (int array[ ][5], int row):这种方式定义的函数,可以传入所有列为5的二维数组,再通过传入的行参数即可访问该二维数组。即是说,定义参数时,必须指出列数,而行数可以省略(但必须通过其他方式指出,以防止越界)
  • 将二维数组作为一维数组使用
    • 在逻辑上二维数组与现实生活情景有更加明确的关联,但是一二维数组在实现上没有本质差别,在内存中均为申请首地址后,一段连续的地址。
    • 可以将二维数组传给调用参数为一维数组的函数,如:
      • 有函数定义为max(int x[ ], int max)
      • 现有一二维数组array[5][6]
      • 则可以通过max( array[0], 5*6)来调用这个使用一维数组的函数

3.结构类型

结构类型的定义

struct someName {
    int val1;
    char str[10];
};
//结合typedef完成定义
typedef struct someName{
    int val1;
    char str[10];
} newName;

结构类型的初始化

newName a = {11, "hello"};

结构类型的使用

通过成员访问符.来调用其中的变量。如:a.val1a.str

4.联合类型

联合类型的定义与结构类似,但是联合定义的变量公用一块内存。即是说,一段时间内只能使用其中的一个变量类型,若同一时间要访问多个联合内的变量,会失败。

联合适用于一次性使用的、不在同一时间内使用的大变量,以来节省空间的使用。

联合类型的定义

union someName{
    int a;
    double b;
    char c;
}

5.指针

指针的定义

dataType *pointerName

  1. 指针定义与一般变量定义的区别在于变量名前有一个*,这个符号在书写时可以跟着dataType也可以跟着pointerName,但编译器将符号的附着点判断在变量名pointerName上。如int* a, b:申请了一个整形变量b,和一个整形指针a,即是说按照int *a, b理解。
  2. 指针应该尽量赋予初值。对于没有初值的变量应当使用空指针变量NULL来完成时初始化。NULLstdio.h中定义的常量,其值为0
  3. 指针的数值一般为整型值,代表着内存编号。

指针的操作

基本操作

  1. 取地址int *a = &valA:符号&将变量的地址赋给了指针
  2. 间接访问*a = 5:符号*用于指针时,等价于使用对应的变量val

用于数组时的操作

  1. 指针的值常初始化做数组的第一个元素,以便于访问,如下。

    int * a, b[10] = {};
    a = &b[0]
    
  2. 此时指针可以与整数进行加减运算,表示指针指向当前元素的上一个、下一个元素

  3. 若有两个同类型的指针分别指向同一个数组,那么这两个指针也可以进行减法运算,表示计算出指针间相隔的元素个数。

用于结构变量时的操作

  1. 若指针指向一个结构变量,那么对于其中的成员变量,可以额外有一种特殊的访问方式,如下:

    struct sth {
        int a;
        double b;
    }
    sth a;
    sth * p;
    cout << (*p).a;//常规方式
    cout << p->b; //特殊的方式
    

指针变量的输出

  1. 当指针变量直接输出时,会输出变量对应的整形值,数值常为十六进制。如:

    int x = 1, *y = &x;
    cout << y;
    //输出的是y的值,亦即x对应的内存地址
    
  2. 当指针变量指向字符串/字符数组时,会直接输出字符串。如:

    char str[] = "string", *p = str;
    cout << p; // 输出结果是string
    cout << *p; //输出结果是s
    
  3. 若要字符串输出的为地址,则要在输出前进行类型转换,换做一个其它类型的指针

    cout << (void *)p;
    //输出的为字符串的地址
    

指针作为传递的参数

使用指针作为函数传递的参数,可以提高传输效率。常用在数组作为参数时使用。如:

int max(int *x, int num){
    //形参为一个指针
    .......;
}
int main(void){
    int a [10];
    ....;
    max(&a[0], 10); 
    //传回数组地址
}

这样避免了传递整个数组的低效。

指针常量与指向常量的指针

使用指针,会有两个效果:

	1. 提高参数传递的效率
	2. 用形参改变了实参的值(调用的函数可能改变原有的、传入的实参的值)
指针常量

而第二个效果常常会产生副作用,为了避免这个副作用,可以使用关键词const构成指针常量指针常量只能改变所指向的内存(即地址值),但不能通过间接访问改变所指向内存的数值(指地址所指向的内容)。这样就避免了形参改变实参,同时还保留了传递参数的功能。

指针常量的声明:dataType *const pointerName

即是在*前加了关键词const以申明指针常量。

需要与指针常量区别的是指向常量的指针常量

指向常量的指针常量

指向常量的指针常量是一个常量,即不能改变它指向的值,也不能通过间接访问改变它所指向的内存。

指向常量的指针常量的声明:const dataType *const pointerName

在指针常量前也加上关键词const,就构成了指向常量的指针常量。

对比

指针常量:dataType *const pointerName

指向常量的指针常量:const dataType *const pointerName

6.动态变量

动态变量是指,在程序在静态的未运行阶段无法确定的变量,只有在程序运行时他才根据程序的需要产生、消亡。

动态变量的创建

动态变量的申请有两种方式

a.关键字new

  1. 使用关键字new,会生成一个指针/地址

  2. 申请单个动态变量:new dataType

int *p;
p = new int;
*p = 1;
  1. 申请数组,数组可以为多维的:new dataType[num]
int *p;
int n;
//一维数组
p = new int[n];

//二维数组
p = new int[n][20]; 
//应当注意高维数目一定得指定,最低一维可以不指定

b.函数malloc()

  1. 函数malloc()返回一个void *变量,即void型变量。在使用前需要对其进行类型转换。
  2. 申请单个动态变量:(dataType *)malloc(sizeof(dataType) )
int *p;
p = (int *)malloc(sizeof(int) );
  1. 申请数组,数组亦可以为多维的:(dataType *)mallloc(sizeof(dataType) * num)
int *p;
p = (int *)malloc(sizeof(int) *n);
//申请了一个一维数组,可以放(0,n-1)个数

p = (int *)malloc(sizeof(int) *n * 20);
//申请了一个二维数组,且同上:高维必须指出,低维可以不指出

c.newmalloc()的区别

主要在于:

  1. new会自动调用构造函数,而malloc()则不会
  2. new自动计算需要的内存,而malloc()需要手动指出
  3. malloc()需要进行类型转换

动态变量的销毁

a.销毁使用new创建的变量

使用new创建的变量最好使用关键字delete销毁

格式:delete pointerName

//销毁单个动态变量
delete p;

//销毁指向动态数组的变量
delete [ ]p;

b.销毁使用malloc()创建的变量

使用malloc()创建的变量最好使用函数free()销毁

格式:free(pointerName)

//free( )因为是函数,所以只有一种使用方法,而没有多种格式
free(p);

c.deletefree()的区别

主要区别如下:

  1. 关键字delete会调用相关类型的析构函数,而函数free( )则不会

d.动态变量造成的内存泄漏

当一个指向动态变量的指针改变指向的变量后,便无法完成对动态变量的访问了,无法对其访问也无法回收对之分配的内存,这种现象叫做内存泄漏

7.函数指针

函数指针的定义

dataType (* pointerName)(argsType)

  1. dayaType是指返回值类型,(argsType)是参数列表,这个参数按序填入即可
  2. 可以使用typedef重命名,格式为:typedef dataType (* newName)(argsType)。即新的类型名为newName,在原来pointerName的位置

函数指针的赋值与调用

  1. 赋值

有两种格式,如下方演示

int (* fp)(int, double);
int demo(int a, double b){
    return a;
}

//方法1
fp = demo;
//方法2
fp = &demo;
  1. 调用

这里调用即是指用函数指针完成对函数的调用,也是函数指针的用处。调用也有两种格式

int (* fp)(int, double);
int demo(int a, double b);

//方法1
(*fp)(10, 2.8);
//方法2
fp(10, 2.9);
posted @ 2022-08-13 09:46  dysonkkk  阅读(70)  评论(0编辑  收藏  举报