6.类C语言有关操作

目录

一. 元素类型说明

二. 数组的定义

三. 内存分配函数

四. C++的动态存储分配

五. C++的参数传递

(1)按值传递方式

 (2)传地址方式

2.1 指针变量做参数

2.2 数组名做参数

2.3 引用类型做参数(重点)

2.4 几点说明


一. 元素类型说明

回顾一下5里面讲的顺序表类型定义:

typedef struct
{
	ElemType *elem;     // 存储空间的基地址
	int length;         // 当前长度
}SqList;                // 顺序表的结构类型为 SqList

Elemtype是顺序表中元素的类型,可以自己定义并更换成需要的类型(int/float/char...),如:

typedef char ElemType

如果是一个复杂类型,我们可以定义一个结构类型:

# define MAXSIZE 1000  //多项式可能达到的最大长度
typedef struct{  //线性表中元素结构数据类型的定义
    float p;  //系数
    int e;  //指数
}Polynomial;

typedef struct{  
    Polynomial *elem;  //存储空间的基地址
    int length;  //多项式中当前项的个数
}SqList;  //多项式的顺序存储结构类型为SqList

二. 数组的定义

数组静态分配:

//数组静态分配
typedef struct{
    ElemType data[MaxSize];
    int length;
}Sqlist; //顺序表类型

数组动态分配,数组的名字存放的是数组的第一个元素data[0]的地址,也就是首地址或者叫基地址。既然他是存放地址的,我们可以定义一个指针变量*data放数组的地址。形式上看起来像是一个指针变量,但是实际上定义了数组:

//数组动态分配
typedef struct{
    ElemType *data; //仍然是定义了数组
    int length;
}Sqlist; //顺序表类型

之所以说数组的本质是指针,是因为在在具体实现上,数组是基于指针实现的,编译器只提供了数组首元素的地址。因此在访问时需要使用首地址+偏移量的形式,所谓的偏移量由下标决定。当我们访问第一个元素是可以使用a[0],也可以使用*a,或者*(a+0);同理当我们访问第二个元素时可以使用a[1],同样的,指针表示为*(a+1)。

对于动态数组怎么分配空间,可以使用内存分配函数:

SqList L;
L.data=(ElemType*)malloc(sizeof(ElemType)*MaxSize);

三. 内存分配函数

这行代码是在C语言中动态分配内存来存储一个名为L的数据结构的元素。ElemType是一个自定义的数据类型,MaxSize是一个表示L中最大元素数量的整数。作下面说明:

malloc(m)函数,开辟m字节长度的地址空间,并返回这段空间的首地址;

sizeof(x)运算,计算变量x的长度;例如之前介绍的多项式计算,每个元素需要8字节;

free(p)函数,释放指针p所指变量的存储空间,即彻底删除一个变量;

具体来说,代码中的malloc函数用于动态分配内存。sizeof(ElemType)表示ElemType类型的对象所占用的字节数。乘以MaxSize后,得到需要分配的总字节数。然后,malloc函数会分配这么多字节的内存,并返回指向该内存块的指针。

最后是内存的划分,将返回的指针强制转换(小括号)为指向ElemType类型的指针(*号),并将其赋值给L.data。这样,L.data就指向了一个具有足够空间存储MaxSize个ElemType类型对象的内存块。通过这样的动态内存分配,我们可以根据实际需要来灵活地调整数据结构的大小,而不需要提前确定元素数量或者固定的内存空间。

此代码需要加载头文件:<stdlib.h>

四. C++的动态存储分配

语法:

new 类型名T (初值列表)

功能:申请用于存放T类型对象的内存空间,并依初值列表赋以初值

结果:成功:T类型的指针,指向新分配的内存;

失败:0(NULL);

int *p1 = new int; //指针变量存储该块分配空间的地址
int *p1 = new int(10); //赋初值10

删除操作:释放指针所指向的内存,P必须是new操作的返回值(指针型);

delete 指针P

五. C++的参数传递

函数调用时传送给形参表的实参必须与形参保持三个一致:类型、个数、顺序

参数传递有两种方式:值传递,地址传递

(1)按值传递方式

参数为整型、实型、字符型等;

void main()
{float a,b;
cin>>a>>b; //输入
swap(a,b);  //函数名,交换a,b,这里a,b作为实参
cout<<a<<endl<<b<<endl; //输出,传值方式a,b的值没有任何变化
}

这里,第二行cin是C++标准库中的输入流对象,用于读取用户输入。>>是输入运算符,用于将输入流中的数据提取出来,并存储到指定的变量中。swap(a, b)是一个函数调用,用于交换两个变量a和b的值。cout是C++标准库中的输出流对象,用于输出数据。<<是输出运算符,用于将数据插入到输出流中。endl是插入一个换行符。

# include <iostream.h>
void swap(float m,float n) //m,n都是形参
{float temp;
temp = m;
m = n;
n = temp;
} //执行完毕以后,m,n被释放

执行完上述代码后,形参m,n的值交换,但是实参a,b的值未发生变化。这就是按值传递,形参和实参采用不同的存储空间。

 (2)传地址方式

包含参数为指针变量,参数为引用类型,参数为数组名三种;

2.1 指针变量做参数

a.形参影响实参

#include <iostream>
using namespace std;

void swap(float *m,float *n) 
{
    float t;
    t = *m; //*m是解引用操作符,用于获取指针m所指向的值。如果m是一个指针,*m就是该指针所指向的值。
    //例如,如果m是一个指向整数的指针,而且它指向的值是5,那么执行t=*m后,变量t的值将是5。
    *m = *n;
    *n = t;
} 

int main()
{
    float a,b,*p1,*p2;
    cin>>a>>b;  //输入
    p1 = &a;  //&取地址运算符,存放a的地址
    p2 = &b;  //存放b的地址
    swap(p1,p2);  //函数名,交换p1,p2,这里p1,p2作为实参
    cout<<"a="<<a<<endl<<"b="<<b<<endl; //输出,传值方式a,b的值变化
}

这里交换的是指针指向的值,因此输出a,b发生了交换:

b.形参不影响实参

#include <iostream>
using namespace std;

void swap(float *m,float *n) 
{
    float *t;
    t = m; //这里把m,也就是a的地址赋值给t
    m = n; 
    n = t; //这里实现的是指针m和n的交换
} //运行结束后,m,n释放掉

int main()
{
    float a,b,c,*p1,*p2;
    cin>>a>>b;  //输入
    p1 = &a;  //&取地址运算符,存放a的地址
    p2 = &b;  //存放b的地址
    swap(p1,p2);  //函数名,交换p1,p2,这里p1,p2作为实参
    cout<<"a="<<a<<endl<<"b="<<b<<endl; //输出,传值方式a,b的值不发生变化
    cout<<*p1<<endl;  //p1,p2指向的值也没有发生变化
    cout<<*p2<<endl;
}

这里a,b都没发生变化,p1,p2指针所指向的值也没发生变化。

2.2 数组名做参数

数组名做参数,传递的是数组的首地址,对形参数组所做的任何改变都将反映到实参数组中。

以下面的代码为例:

#define _CRT_SECURE_NO_WARNINGS
//添加到头行,添加到头文件后还是会出警告的
#include <iostream>
#include <cstring>
using namespace std;

void sub(char b[]) //指向char类型的指针b,也可以写成*b
{
    string s; 	
    s = "world"; 	
    strcpy(b, s.c_str());  //将s中的内容拷贝到b指向的位置
} 

int main(void)
{
    char a[10] = "hello";
    sub(a); //数组名做参数传递,实际上就是传递了首地址
    cout<<a<<endl;  //输出a,这时应该打印world
}

运行结果:

2.3 引用类型做参数(重点,以后常用)

什么是引用-用来给对象提供一个替代的名字。

#include <iostream>
using namespace std;

int main()
{
    int i=5;
    int &j=i; //j是一个引用类型,代表i的一个替代名
    //i的值发生变化时,j的值也发生变化
    //也可以理解为i,j是同一块地址,使用相同内存空间
    i=7;
    cout<<"i="<<i<<endl;
    cout<<"j="<<j<<endl;
}

输出:i=7;j=7;接下来还考虑之前的swap交换函数:

#include <iostream>
using namespace std;

void swap(float &m,float &n) //引用型参数,m引用了a,n引用了b
{
    float temp;
    temp = m;  //因此对m的操作就是等价于对a的操作
    m = n;
    n = temp;
} 

int main()
{
    float a,b;
    cin>>a>>b;  //输入
    swap(a,b);  //函数名,a,b作为实参
    cout<<"a="<<a<<endl<<"b="<<b<<endl; //输出,传地址方式a,b的值发生变化
}

2.4 几点说明

(1)传递引用给函数与传递指针的效果是一样的,形参变化实参也发生变化;

(2)引用类型作形参,在内存中并没有产生实参的副本,它直接对实参操作;而一般变量作参数,形参与实参就占用不同的存储单元,所以形参变量的值是实参变量的副本。因此,当参数传递的数据量较大时,用引用类型做形参比用一般变量传递参数的时间和空间效率都好;

(3)指针参数虽然也能达到与使用引用的效果,但在被调函数中需要重复使用“*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北京地铁1号线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值