C/C++选择部分数组元素为指定的值:memset()和fill()


一、memset()

C/C++通用

1.头文件

C:#include<string.h>

C++:#include<cstring> or #include<string.h>

2.函数原型

【作用】:将已开辟内存空间_Dst的首_Size字节的值设为值_Val

void *memset(void *_Dst, int _Val, size_t _Size)

【例子】:

int a[5];
memset(a, 0, sizeof(a));

【解析:memset函数是以字节为单位进行赋值的】

  1. 取值过程:取表示值的_Val参数的一个低位字节Byte
    我们都知道int类型是4个字节,一个字节Byte是8bit。比如例子中传入0,其实是0x0000 000000000000 00000000 00000000 00000000),十六进制下的一位表示4位bit,即两位十六进制表示一个字节。取得就是 0x0000 00 00 (00000000 00000000 00000000  00000000 ) \text{0x0000 00\boxed{00}(00000000 00000000 00000000 \boxed {00000000})} 0x0000 0000(00000000 00000000 00000000 00000000)
    同理,-10xffff ffff11111111 11111111 11111111 11111111),而511是0x0000 01ff00000000 00000000 00000001 11111111)的后八位都为0xff11111111),所以int a[5]赋值memset(a, -1, sizeof(int)*5)memset(a, 511, sizeof(int)*5)所赋值的结果是一样的都为-1
  2. 赋值过程
    _Val取的一个低位字节为单位,填充满所要初始化的空间。比如上面的例子中用0赋值得到数组元素都是0,就是因为a[0]就是用赋值了四个0x00字节,组合到一起刚好又是0

【解析:_Dst就是地址位置】
这东西就是获得一个指向开始位置的地址嘛,那么就是获得数组的首地址的那几种方法嘛。

3.使用

(1)赋值int数组

如果用int类型赋值的话,要取每个字节都相同的值,因为别的值因为字节拆分组合起来就不是本身了。

比如用0或-1初始化,用0x3f3f3f3f(表示ACM中的无穷大)。

int a[5];

memset(a, 0, sizeof(a));
memset(&a[0], 0, sizeof(a));
memset(a, 0, 5 * sizeof(int));
int a[5][5];

memset(a, 0, sizeof(a));
memset(a[0], 0, sizeof(a));
memset(&a[0][0], 0, sizeof(a));
memset(a, 0, 25 * sizeof(int));

(2)赋值char数组

如果用char类型赋值的话,就是char本身。

因为char类型可以表示为ASCII码表示的int值,比如A就是65。

一般是赋值'\0''0''1'之类的(要加单引号)。

char a[5];
memset(a, 'A', sizeof(a));
for (int i = 0; i < 5; i++)
{
    cout << a[i] << " ";
}
cout << endl;
// A A A A A

(3)结构体

结构体也是按照字节为单位存储的

/* 一般的结构的清空操作 */
struct Student
{
    char name[16];
    int id;
};
struct Student Tom;
// 因为char数组只要出现'\0'就代表结束了
Tom.name[0] = {'\0'};
Tom.id = 0;

/* 用memset()清空结构体 */
memset(&Tom, 0, sizeof(Tom));
// 注意&

如果是结构体数组:

struct Student students[10];
memset(students, 0, sizeof(students) * 10);

PS:【需要再研究下,结构体对齐问题,比如name[17]时;“如果结构体中有数组的话还是需要对数组单独进行初始化处理的。”啥意思】

二、fill()

C++专用

1.头文件

#include <iostream>
using namespace std;

2.函数原型

作用:将val赋给范围内的所有元素[first, last]

fill 的前两个参数是定义序列的正向迭代器,第三个参数是赋给每个元素的值。

只要在类型表示的范围内,val随便赋值

template <class ForwardIterator, class T>
  void fill (ForwardIterator first, ForwardIterator last, const T& val)
{
  while (first != last) {
    *first = val;
    ++first;
  }
}

【解析:firstlast其实也是获得地址的位置,但是有限制】
它是用*first来获得值修改的,所以只能套一层,*p直接就是值,不能**p才获得值。

3.例子

(1)数组

int a[5];

fill(a, a + 5, 0);
fill(&a[0], a + 5, 0);
fill(&a[0], &a[5], 1);		// 因为是"不到last"
fill(&a[0], a + sizeof(a) / sizeof(int), 1);
fill(&a[0], a + sizeof(a) / sizeof(a[0]), 1);
int a[5][5];

// fill(a, a + 5 * 5, 0);			// 报错,'const int' to 'int [5]'
// fill(&a, &a + 5 * 5, 0);			// 报错,'const int' to 'int [5][5]'
// fill(&a[0], &a[0] + 5 * 5, 0);	// 报错,'const int' to 'int [5]'
fill(a[0], a[0] + 5 * 5, 0);
fill(&a[0][0], &a[5][5], 0);
fill(&a[0][0], &a[0][0] + 5 * 5, 0);
fill(&a[0][0], &a[0][0] + sizeof(a) / sizeof(int), 0);

三、总结

1.都可以挑选位置设置

并不局限于只是全部的元素

int a[5] = {};

memset(&a[1], -1, sizeof(int) * 2);
// memset(&a[1], -1, (&a[3] - &a[1]) * sizeof(a[0]));

// fill(&a[1], &a[3], -1);

for (int i = 0; i < 5; i++)
{
    cout << a[i] << " ";
}
int a[5][5] = {};

memset(&a[1][2], -1, (&a[3][4] - &a[1][2]) * sizeof(a[0][0]));

// fill(&a[1][2], &a[3][4], 0);

for (int i = 0; i < 5; i++)
{
    for (int j = 0; j < 5; j++)
    {
        cout << a[i][j] << " ";
    }
    cout << endl;
}
cout << endl;

2.sizeof()的陷阱

就是获取所占空间大小的字节数(= 单个元素类型的字节数×数组元素个数),但注意数组传参的陷阱。

(win64下)数组传参进来是一个指针,而指针的类型是8个字节。而不是应该的5x4=20

void fun(int a[5])
{
	cout << sizeof(a) << endl;
	// 8
}

Reference

memset-百度百科

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值