【C++ -> 容器初始化】結構體巢狀複雜結構初始化
案例簡述
最近在設計資料結構時,資料之間較為複雜,資料結構如下:
typedef struct tagDataInfo
{
long offs; // 索引
char name[20]; // 姓名
std::list<int> ord_list; // 定單索引列表
std::map<std::string, std::string> str_map; // 編號對應管理
tagDataInfo() { memset(this, 0, sizeof(*this)); };
} DataInfo;
程式執行的時候,程式core dump了,經過查閱資料以及gdb除錯,發現使用memset並沒有像預期那樣把所有元素都初始化。
知識梳理
結構很簡單,就是為了體現資料之間的對應關係。
老生常談的函式介紹:
函式原型:
void *memset(void *s, int ch, size_t n);
函式功能:
將s所指向的某一塊記憶體中的前n個位元組的內容全部設定為ch指定的ASCII值,
第一個值為指定的記憶體地址,塊的大小由第三個引數指定,這個函式通常為新申請的記憶體做初始化工作,其返回值為指向s的指標,它是對較大的結構體或陣列進行清零操作的一種最快方法。
引入標頭檔案
<memory.h>或<string.h>
應用場景:
memset函式通常用來對一塊已經分配地址的記憶體進行初始化,並且通常初始化為0或者字元’\0’。如上述例子!
注意事項:
(1)memset中的第三個引數一定要使用sizeof操作符,因為每個系統下對型別長度的定義可能不一樣。
(2)memset中的第一個引數一定要是一個已知的、已經被分配記憶體的地址,否則會出錯。
(3)大家可能比較疑惑,memset的第一個引數已經有了被初始化空間的首地址,為什麼還要返回一個void*的指標去指向這個地址呢?這裡之所以還要返回這個指標是為了實現鏈式程式設計,所謂鏈式程式設計,舉個例子大家就明白了。
(4)最後一點,也是最重要的一點。一定要注意,memset是按照位元組對待初始化空間進行初始化的,也就是說,函式裡面的第二個引數的那個初值(一般為0)是按照一個一個位元組往第一個引數所指區域賦值的,所以,對於單位元組資料型別(char)可以初始化為任意支援的值,都沒有問題,但是對於非多位元組資料型別只能初始化為0,而不能初始化成別的初值,因為對所有位元組按任意順序賦值0的結果都是0,而如果初始化為其他的值,就會一個位元組一個位元組的進行賦值,從而出現奇怪的結果。比如說,上面的例3之所以沒有出錯就是因為初始化為0,但是如果初始化為1,那麼因為int一般是4個位元組,那麼相當於將一個int元素初始化成了0000 0001 0000 0001 0000 0001 0000 0001,這樣對於一個int元素肯定不是1,而是一個很大的數,結果出乎意料,所以一定要記住這一點,非常重要!!!
引申:何謂鏈式程式設計?
舉例:
#include <iostream>
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
int main()
{
// 鏈式程式設計
int i = 0;
char cBuf [10];
char cBuf1[10];
// 這裡是關鍵!!!
memcpy(cBuf1, memset(cBuf, 'a', sizeof(char) * 10), sizeof(char) * 10);
for (i = 0; i < 10; ++i)
{
printf("%c", cBuf[i]);
}
printf("\n");
for (i = 0; i < 10; ++i)
{
printf("%c", cBuf1[i]);
}
printf("\n");
return 0;
}
從上面這個例子中就可以看出,在memcpy這個函式中,直接使用了memset的返回值,用其來拷貝cBuf1這個字元陣列,這樣就可以直接連起來寫,看起來十分方便。但是這個例子的應用形式卻很少,只是為了說明這個問題才這樣寫的,這種結構在很多函式庫裡面比較常見,比如字串操作函式等,但是鏈式程式設計也使得程式碼變得有些不直觀,所以要有所取捨。
問題剖析
1)上述也說了,memset是以位元組為單位,初始化記憶體塊
2)當結構體中包含指標時,在使用memset初始化要特別注意:
#include <iostream>
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
int main()
{
struct Parameters {
int x;
int* p_x;
};
Parameters par;
par.p_x = new int[10];
memset(&par, 0, sizeof(par));
// 輸出nil
printf("地址: %p \n", par.p_x);
int* ptr = new int[10];
// 正確輸出
printf("地址: %p \n", ptr);
return 0;
}
當memset初始化時,並不會初始化p_x指向的int陣列單元的值,而會把已經分配過記憶體的p_x指標本身設定為0,造成記憶體洩漏。
同理,對std::vector等資料型別,顯而易見也是不應該使用memset來初始化的。
正確Init
typedef struct tagDataInfo
{
long offs; // 索引
char name[20]; // 姓名
std::list<int> ord_list; // 定單索引列表
std::map<std::string, std::string> str_map; // 編號對應管理
tagDataInfo() : offs(0)
{
memset(name, '0', sizeof(char) * 20);
ord_list.clear();
str_map.clear();
};
} DataInfo;
相關推薦
【C++ -> 容器初始化】結構體巢狀複雜結構初始化
案例簡述 最近在設計資料結構時,資料之間較為複雜,資料結構如下: typedef struct tagDataInfo { long offs; // 索引 char name[20]; /
第22節 C語言結構體之結構體巢狀、結構體指標與結構體陣列的程式碼實現
結構體 #include <stdio.h> //第一步 struct Student { //學號 int no; //姓名 char name[20]; //性別 char
C語言結構體的前向宣告,以及結構體巢狀const結構體成員的問題
如果你在宣告一個結構體A時,要使用一個未宣告的結構體B時,該怎麼辦?如下: #include <stdio.h> typedef struct demo{ struct stu test; const int test2; int te
結構體巢狀與結構體指標
struct和typedef struct 首先是結構體的定義格式分三塊來講述: 1 首先://注意在C和C++裡不同 在C中定義一個結構體型別要用typedef: typedef struct Student { int a;
day07 結構體 匿名結構體 結構體的初始化 訪問 結構體巢狀 結構體的儲存空間 結構體陣列
//結構體的定義/* struct 結構體的定義{ 資料型別成員變數1; 資料型別成員變數2; ..... 資料型別成員變數n; }; 注意“;” *///typedef(第一種方式)//先定義結構體,在說明結構體變數//struct myPoint{// float x;//行座標//
C++ 結構體巢狀
該部落格主要是示例如何使用結構體巢狀進行函式變數的封裝傳遞。 主要任務是使用一個結構體包含一些目標的名稱、距離、角度資訊。不同場景下的目標數量是不一樣的,所以不能使用固定的陣列來進行儲存,使用陣列太大時浪費空間,太小是又擔心不能正確儲存資訊。所以建議使用結構體巢
c語言結構體巢狀的對齊方式
1:在程式碼中有結構體巢狀的方式,又需要獲取每個變數的地址。那麼需要了解結構體巢狀和單一結構體的一些對齊方面的規則。2:對於嵌入式的裝置來說,對齊很重要,有些cpu不支援不對齊的訪問方式,有的cpu支援,只是效率上會降低。3:arm中預設編譯的時候會進行對齊。規則一:結構體中
C語言_結構體巢狀和字串陣列的表示_plusC14.3
#include<stdio.h> #define LEN 20 const char *mgs[5]= {"qqqq","wwww","EEEEEEE","RRRR","TTTTT" }; struct apple {char smell[LEN];char
C語言之結構體巢狀一級指標和二級指標
指標是C語言的精華,也是c中最難的部分;為了鍛鍊和提高自己對指標的理解,特在結構體中巢狀一級指標和二級指標來加深對。 #include<stdio.h> #include <string.h> #include<stdlib.h&
C語言-結構體指標及結構體巢狀
C語言中結構體是一種構造型別,和陣列、基本資料型別一樣,可以定義指向該種類型的指標。結構體指標的定義類似其他基本資料型別的定義,格式如下 struct 結構體名 * 指標名; 比如: struct person{char[20] name; int age;};//先定義一
jchdl - RTL例項 - And2And(結構體巢狀的使用)
https://mp.weixin.qq.com/s/PQIPkDymvcGc_re8ux50vA 結構體可以巢狀使用。 參考連結 https://github.com/wjcdx/jchdl/blob/master/src/org/jchdl
1263 STL map和結構體巢狀使用。
例題:HDU - 1263 夏天來了~~好開心啊,呵呵,好多好多水果~~ Joe經營著一個不大的水果店.他認為生存之道就是經營最受顧客歡迎的水果.現在他想要一份水果銷售情況的明細表,這樣Joe就可以很容易掌握所有水果的銷售情況了. Input 第一行正整數N(0<
NUC140 之共用體和結構體巢狀
共用體和結構體巢狀的情況最早見於NUC1XXX的庫函式,後來用的非常順手, 看下面的程式碼: typedef union { //定義一種共用體,它包含兩個成員,一個是8位的總的錯誤訊號(錯誤暫存器位元組1所用) uint8_t error_sampl
go結構體巢狀的切片陣列
package main import ( "fmt" ) type XCDataStu struct { Id int `json:"id" xorm:"id"` Name string `json:"name" xorm:"name"` } ty
結構體巢狀時的sizeof運算
如果結果體中的成員包括陣列或者其他結構體,在資料對齊時,要以結構體中最深層的基本資料型別為準。所謂結構體中最深層的基本資料型別是指:如果結構體中的成員為複雜資料型別,不應以複雜資料型別所佔空間作為資料對齊的標準,而應深入複雜資料型別內部,檢視其所包含的基本資料型別所佔空間。
go語言基礎 結構體巢狀
go語言當中的聚合和繼承都是模擬出來的,子類是可以使用父類裡的欄位或功能結構體的巢狀type A struct{ //父類name stringage int}type B struct{ //子類a A // 模擬聚合關係.....}type C struct{ /
結構體巢狀二級指標
#include <stdio.h> #include <stdlib.h> #include <
【C語言經典例項】-指向結構體的指標變數
本例項通過結構體指標變數實現在窗體上顯示學生資訊,執行程式後,將學生資訊輸出在窗體上,效果如圖所示: 在本例項中,我們先宣告一個結構體變數,並定義一個指標變數指向struct student型別的資料,程式碼如下: #include<stdio.h> #inc
C語言結構體的位元組對齊例項【C語言筆試題】
一、筆試題目:在一個64位的作業系統中定義如下結構體: <span style="font-family:Microsoft YaHei;font-size:12px;">struct st_task { uint16_t id; uint32
linux C 結構體struct的定義和初始化
struct 定義: struct test { int a; long b; float c; char d; char e[]; }tt1,tt2;//物件宣告列表緊跟struct定義 struct test tt3,tt4;//單獨宣告物件列表 //宣告一個沒結構體名