我正在試驗 C 并發現了這一點,const char*并且const char[]在下面的代碼中表現得非常不同。如果我沒有很好地表達這個問題,真的很抱歉,因為我不清楚代碼中發生了什么。
#include <iostream>
#include <vector>
// This version uses <const char[3]> for <myStr>.
// It does not work as expected.
struct StrStruct
{
const char myStr[3];
};
// This program extracts all the string elements in <strStructList> and copy them to <strListCopy>
int main()
{
StrStruct strStruct1{"ab"};
StrStruct strStruct2{"de"};
StrStruct strStruct3{"ga"};
std::vector<StrStruct> strStructList{strStruct1, strStruct2, strStruct3};
std::vector<const char*> strListCopy{};
for (StrStruct strStructEle : strStructList)
{
strListCopy.push_back(strStructEle.myStr);
std::cout << "Memory address for the string got pushed back in is "
<< &strStructEle.myStr << std::endl;
std::cout << "Memory address for the first element of the string got pushed back in is "
<< (void *) &strStructEle.myStr[0] << "\n" <<std::endl;
}
std::cout << "Show content of <strListCopy>:" << std::endl;
for (const char*& strEle : strListCopy)
{
std::cout << strEle << std::endl;
}
}
以下是它的輸出:
Memory address for the string got pushed back in is [address#99]
Memory address for the first element of the string got pushed back in is [address#99]
Memory address for the string got pushed back in is [address#99]
Memory address for the first element of the string got pushed back in is [address#99]
Memory address for the string got pushed back in is [address#99]
Memory address for the first element of the string got pushed back in is [address#99]
Show content of <strListCopy>:
ga
ga
ga
但是,如果我只是簡單地更改實作 StrStruct
從:
// This version uses <const char[3]> for <myStr>.
// It does not work as expected.
struct StrStruct
{
const char myStr[3];
};
到
// This version uses <const char*> for <myStr>.
// It works as expected.
struct StrStruct
{
const char* myStr;
};
程式的輸出變成這樣:
Memory address for the string got pushed back in is [address#10]
Memory address for the first element of the string got pushed back in is [address#1]
Memory address for the string got pushed back in is [address#10]
Memory address for the first element of the string got pushed back in is [address#2]
Memory address for the string got pushed back in is [address#10]
Memory address for the first element of the string got pushed back in is [address#3]
Show content of <strListCopy>:
ab
de
ga
令我困惑的是以下幾點:
為什么在第一個版本中所有字串都具有相同的值?我嘗試在 for each 回圈中使用
const strStruct&而不是strStruct解決問題,但我不明白如何。為什么做事
const char*和const char[]行為如此不同?由于以下原因,我認為它們大致相同:
const char myChars[] = "abcde";
const char* myCharsCopy = myChars;
std::cout << myChars << " vs " << myCharsCopy << std::endl;
它列印出來abcde vs abcde,您可以直接為const char[]to賦值const char*而不會出現任何錯誤。
- 為什么改成
const char[]能const char*解決問題?
uj5u.com熱心網友回復:
理解其余部分所需的基礎知識:
陣列和衰減
struct StrStruct
{
const char myStr[3];
};
包含資料
struct StrStruct
{
const char * myStr;
};
指向資料。
陣列衰減為指標,但本身不是指標。
const char myChars[] = "abcde";
制作一個大小完全正確的陣列(六個字符、五個字母和空終止符)來保存"abcde"字串并將其復制到陣列中。請注意,這不一定是const。
const char* myCharsCopy = myChars;
定義一個指向 a 的指標char并將陣列分配給它myChars。myChars在這個程序中自動衰減到一個指標。myCharsCopy不是的副本myChars;它只保存 的地址myChars。注意,只要myChars是const,myCharsCopy一定是const。另請注意,您不能分配給陣列,并且幾乎不可能復制陣列,除非您將其放置在另一個資料結構中。您通常可以做的最好的事情是將陣列中的內容復制到另一個陣列(memcpy或strcpy取決于目標以及陣列是否為空終止字符陣列)。
請注意,在許多用途中,例如一個函式引數,const char[]其const char*含義相同。
void func(const char a[], // accepts constant pointer to char
const char * b) // also accepts constant pointer to char
這些東西變得非常奇怪,原因(大部分)在 1970 年代非常有意義。今天,我強烈建議您使用類似std::vector和 的庫容器,std::array而不是原始陣列。
基于范圍的 for 回圈
除非您另外指定,否則基于范圍的 for 回圈對串列中專案的副本進行操作。在體內
for (StrStruct strStructEle : strStructList)
在回圈的第一次迭代中,strStructEle不是strStruct1或者甚至副本strStructEle,它位于strStructList,它是第三相同物件。副本在正文結束時被銷毀,從而釋放所使用的存盤空間。
和
for (StrStruct & strStructEle : strStructList)
回圈將對 中的專案的參考進行操作strStructList,因此不會制作任何副本。
既然你跟上了速度......
第 1 點
為什么在第一個版本中所有字串都具有相同的值?我嘗試在 for each 回圈中使用 const strStruct& 而不是 strStruct 來解決問題,但我不明白如何解決。
自從
struct StrStruct
{
const char myStr[3];
};
包含復制StrStruct. 代碼將資料結構復制到這里
std::vector<StrStruct> strStructList{strStruct1, strStruct2, strStruct3};
而且,更重要的是輸出,這里
for (StrStruct strStructEle : strStructList) // strStructEle copied, so data in it is copied
{
strListCopy.push_back(strStructEle.myStr); //strStructEle.myStr decays to pointer,
// and pointer is stored in strListCopy
// this is not really a copy it's a pointer
// to data stored elsewhere
std::cout << "Memory address for the string got pushed back in is "
<< &strStructEle.myStr << std::endl; // print address of array
std::cout << "Memory address for the first element of the string got pushed back in is "
<< (void *) &strStructEle.myStr[0] << "\n" <<std::endl;
// prints address of the first item in the array, the same as the array
} // strStructEle is destroyed here, so the stored pointer is now invalid.
// Technically anything can happen at this point
但在這種情況下,任何可能發生的事情似乎strStructEle都是在回圈的下一次迭代中重復使用存盤。這就是為什么所有存盤的指標看起來都相同的原因。他們是一樣的。它們是在不同時間點都駐留在同一位置的不同物件。所有這些物件都已過期,因此嘗試查看它們并不是一個好主意。
const strStruct&“修復”了問題,因為沒有復制。每次迭代對不同位置的不同物件而不是同一位置的不同物件進行操作。
第 3 點
為什么改成
const char[]能const char*解決問題?
如果myStr是指標而不是陣列,情況就不一樣了
for (StrStruct strStructEle : strStructList) // strStructEle copied, so data in it is copied
// BUT! The data in it is a pointer to data
// stored elsewhere that is NOT copied
{
strListCopy.push_back(strStructEle.myStr); //strStructEle.myStr is a pointer and is
// directly stored in strListCopy
// this is still not a copy
std::cout << "Memory address for the string got pushed back in is "
<< &strStructEle.myStr << std::endl; // print address of pointer, not what
// it points at
std::cout << "Memory address for the first element of the string got pushed back in is "
<< (void *) &strStructEle.myStr[0] << "\n" <<std::endl;
// prints address of the first item pointed to by the pointer,
// and will be a totally different address
}
第 2 點
為什么 const char* 和 const char[] 的行為如此不同?由于以下原因,我認為它們大致相同...
這是上面解釋的陣列衰減的結果。
旁白:
vector當 s 被允許直接包含(并擁有)他們正在收集的資料時,它們處于最佳狀態。它們處理所有記憶體管理,并將資料保存在一個漂亮的、易于快取的塊中。
uj5u.com熱心網友回復:
基于Yakov Galka和評論區的user4581301
在回答之前需要清除的幾件事:
const char*和之間的區別const char[]:
從概念上講:
const char* 是指向a的指標 const char
const char[] 是字符陣列本身。
在代碼方面:
const char*存盤一個記憶體地址,并且它自己的記憶體地址和它存盤的不同。
const char[] 存盤陣列中第一個元素的記憶體地址,并且它自己的記憶體地址與它存盤的相同。
const char myCharsArray[] = "abcde"; // Writing like this guarrentees you have an null terminator at the end
const char* myCharsPointer = "qwert\0";
std::cout << "The memory address for <myCharsArray> is "
<< &myCharsArray
<< std::endl;;
std::cout << "The memory address for the first element in <myCharArray> is "
<< (void *) &myCharsArray[0]
<< std::endl;
std::cout << "The memory address for <myCharsPointer> is "
<< &myCharsPointer
<< std::endl;
std::cout << "The memory address for the first element in <myCharsPointer> is "
<< (void *) &myCharsPointer[0]
<< std::endl;
它的輸出是這樣的:
The memory address for <myCharsArray> is [address#10]
The memory address for the first element in <myCharArray> is [address#10]
The memory address for <myCharsPointer> is [address#88]
The memory address for the first element in <myCharsPointer> is [address#99]
要回答這三個問題:
問題 1:
在第一個版本中,std::vector::push_back不斷添加它復制的字符陣列中第一個元素的地址,這也是strStructEle.myStr它自己永遠不會改變的地址。最后,串列是一堆值完全相同的記憶體地址。
通過使用const strStruct&,使用對原始內容的參考。因此,它們唯一且真實的記憶體地址被復制到串列中。
問題2:
差異如上所述。
問題 3:
它允許傳遞原始字符陣列的原始記憶體地址,而不是復制原始字符陣列的內容,然后復制臨時物件的記憶體地址。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/365838.html
上一篇:當應該作業的內容不起作用時,如何鉆入JSON物件以獲取陣列
下一篇:如何從陣列中洗掉重復項
