假设我有一个空终止字符串向量,其中一些可能是空指针。我不知道这是否合法。这是一个学习练习。
示例代码
std::vector<char*> c_strings1;
char* p1 = "Stack Over Flow";
c_strings1.push_back(p1);
p1 = NULL; // I am puzzled you can do this and what exactly is stored at this memory location
c_strings1.push_back(p1);
p1 = "Answer";
c_strings1.push_back(p1);
for(std::vector<char*>::size_type i = 0; i < c_strings1.size(); ++i)
{
if( c_strings1[i] != 0 )
{
cout << c_strings1[i] << endl;
}
}
请注意,即使我在位置 c_strings1[1]
处有 NULL,向量的大小仍为 3
问题。如何使用 std::vector
重写此代码
当您推送空值时,向量中到底存储了什么?
编辑
我的问题的第一部分已经得到彻底回答,但第二部分还没有得到彻底回答。至少我不满意。我确实想看看vector的用法;
;不是一些嵌套变体或 std::vector
这些是熟悉的。所以这是我尝试过的(提示:它不起作用)
std::vector<char> c_strings2;
string s = "Stack Over Flow";
c_strings2.insert(c_strings2.end(), s.begin(), s.end() );
// char* p = NULL;
s = ""; // this is not really NULL, But would want a NULL here
c_strings2.insert(c_strings2.end(), s.begin(), s.end() );
s = "Answer";
c_strings2.insert(c_strings2.end(), s.begin(), s.end() );
const char *cs = &c_strings2[0];
while (cs <= &c_strings2[2])
{
std::cout << cs << "\n";
cs += std::strlen(cs) + 1;
}
Say I have a vector of null terminates strings some of which may be null pointers. I don't know even if this is legal. It is a learning exercise.
Example code
std::vector<char*> c_strings1;
char* p1 = "Stack Over Flow";
c_strings1.push_back(p1);
p1 = NULL; // I am puzzled you can do this and what exactly is stored at this memory location
c_strings1.push_back(p1);
p1 = "Answer";
c_strings1.push_back(p1);
for(std::vector<char*>::size_type i = 0; i < c_strings1.size(); ++i)
{
if( c_strings1[i] != 0 )
{
cout << c_strings1[i] << endl;
}
}
Note that the size of vector is 3 even though I have a NULL at location c_strings1[1]
Question. How can you re-write this code using std::vector<char>
What exactly is stored in the vector when you push a null value?
EDIT
The first part of my question has been thoroughly answered but not the second. Not to my statisfaction at least. I do want to see usage of vector<char>
; not some nested variant or std::vector<std::string>
Those are familiar. So here is what I tried ( hint: it does not work)
std::vector<char> c_strings2;
string s = "Stack Over Flow";
c_strings2.insert(c_strings2.end(), s.begin(), s.end() );
// char* p = NULL;
s = ""; // this is not really NULL, But would want a NULL here
c_strings2.insert(c_strings2.end(), s.begin(), s.end() );
s = "Answer";
c_strings2.insert(c_strings2.end(), s.begin(), s.end() );
const char *cs = &c_strings2[0];
while (cs <= &c_strings2[2])
{
std::cout << cs << "\n";
cs += std::strlen(cs) + 1;
}
发布评论
评论(6)
您没有字符串的
向量
- 您有一个指向字符的指针的向量
。 NULL 是一个完全有效的字符指针,它恰好不指向任何东西,因此它存储在向量中。请注意,您实际存储的指针是指向 char 文字的指针。字符串不会被复制。
将 C++ 风格的向量与 C 风格的 char 指针混合起来没有多大意义。这样做并不违法,但是像这样混合范例通常会导致混乱和混乱。破解代码。
为什么不使用
vector
而不是使用vector
或vector
呢?编辑
根据您的编辑,您似乎想要做的是将多个字符串展平为单个
vector
,并在每个展平字符串之间使用 NULL 终止符。这是实现此目的的简单方法:
You don't have a
vector
of strings -- you have avector
of pointer-to-char. NULL is a perfectly valid pointer-to-char which happens to not point to anything, so it is stored in the vector.Note that the pointers you are actually storing are pointers to char literals. The strings are not copied.
It doesn't make a lot of sense to mix the C++ style
vector
with the C-style char pointers. Its not illegal to do so, but mixing paradigms like this often results in confused & busted code.Instead of using a
vector<char*>
or avector<char>
, why not use avector<string>
?EDIT
Based on your edit, it seems like what your'e trying to do is flatten several strings in to a single
vector<char>
, with a NULL-terminator between each of the flattened strings.Here's a simple way to accomplish this:
所以,
如果你注意到的话,这三个的类型是完全相同的。它们都是
char *
。因此,我们希望它们在内存中也具有相同的大小。您可能认为它们在内存中具有相同的大小没有意义,因为 p3 比 p1 短。实际发生的情况是,编译器在编译时会找到程序中的所有字符串。在本例中,它将找到“Stack Over Flow”和“Answer”。它将把它们扔到内存中它知道的某个固定位置。然后,当您尝试说出
p3 = "Answer"
时,编译器实际上会将其转换为p3 = 0x123456A0
之类的内容。因此,无论使用哪种版本的 Push_back 调用,您都只是将指针推入向量,而不是实际的字符串本身。
向量本身不知道也不关心
NULL char *
是空字符串。因此,在计数时,它发现您已将三个指针推入其中,因此它报告的大小为 3。So,
If you notice, the type of all three of those is exactly the same. They are all
char *
. Because of this, we would expect them all to have the same size in memory as well.You may think that it doesn't make sense for them to have the same size in memory, because p3 is shorter than p1. What actually happens, is that the compiler, at compile-time, will find all of the strings in the program. In this case, it would find
"Stack Over Flow"
and"Answer"
. It will throw those to some constant place in memory, that it knows about. Then, when you attempt to say thatp3 = "Answer"
, the compiler actually transforms that to something likep3 = 0x123456A0
.Therefore, with either version of the push_back call, you are only pushing into the vector a pointer, not the actual string itself.
The vector itself, doesn't know, or care that a
NULL char *
is an empty string. So in it's counting, it sees that you have pushed three pointers into it, so it reports a size of 3.我有一种有趣的感觉,你真正想要的是让向量包含类似“Stack Over Flow Answer”的内容(可能在“Answer”之前没有空格)。
在这种情况下,您可以使用 std::vector,您只需推送整个数组,而不仅仅是指向它们的指针。
这无法通过
push_back
来完成,但是vector
有一个接受范围的insert
方法。这使用单个连续缓冲区来存储多个以 null 结尾的字符串。将空字符串传递给
push_back
会导致显示空字符串。I have a funny feeling that what you would really want is to have the vector contain something like
"Stack Over Flow Answer"
(possibly without space before"Answer"
).In this case, you can use a
std::vector<char>
, you just have to push the whole arrays, not just pointers to them.This cannot be accomplished with
push_back
, howevervector
have aninsert
method that accept ranges.This uses a single contiguous buffer to store multiple null-terminated strings. Passing a null string to
push_back
results in an empty string being displayed.一个
NULL
。您正在存储指针,并且NULL
是指针的可能值。为什么这在某种程度上是出乎意料的?另外,使用
std::string
作为值类型(即std::vector
),char*
应该'除非 C 互操作需要,否则不要使用。要使用std::vector
复制代码,您需要std::vector>
。A
NULL
. You're storing pointers, andNULL
is a possible value for a pointer. Why is this unexpected in any way?Also, use
std::string
as the value type (i.e.std::vector<std::string>
),char*
shouldn't be used unless it's needed for C interop. To replicate your code usingstd::vector<char>
, you'd needstd::vector<std::vector<char>>
.在 STL 容器中存储指针时必须小心 - 复制容器会导致浅复制和类似的情况。
关于您的具体问题,向量将存储 char* 类型的指针,无论该指针是否指向某个东西。由于某种原因,您完全有可能希望在该向量中存储 char* 类型的空指针 - 例如,如果您决定稍后从向量中删除该字符串怎么办?向量仅支持 push_back 和 pop_back 的摊销常量时间,因此,如果您要删除该向量内的字符串(但不是在末尾),您很可能希望快速将其设置为空并节省一些时间。
继续 - 我建议制作一个 std::vector >如果您想要一个看起来像您想要的动态字符串数组。
您提到的 std::vector 与您的原始代码相比是无用的,因为您的原始代码存储动态字符串数组,而 std::vector 仅保存一个动态可更改的字符串(因为字符串本质上是一个字符数组) 。
You have to be careful when storing pointers in STL containers - copying the containers results in shallow copy and things like that.
With regard to your specific question, the vector will store a pointer of type char* regardless of whether or not that pointer points to something. It's entirely possible you would want to store a null-pointer of type char* within that vector for some reason - for example, what if you decide to delete that character string at a later point from the vector? Vectors only support amortized constant time for push_back and pop_back, so there's a good chance if you were deleting a string inside that vector (but not at the end) that you would prefer to just set it null quickly and save some time.
Moving on - I would suggest making a std::vector > if you want a dynamic array of strings which looks like what you're going for.
A std::vector as you mentioned would be useless compared to your original code because your original code stores a dynamic array of strings and a std::vector would only hold one dynamically changable string (as a string is an array of characters essentially).
NULL就是0。值为0的指针是有意义的。但是值为 0 的 char 具有不同的含义。它用作分隔符来显示字符串的结尾。因此,如果您使用
std::vector
和push_back
0,向量将包含值为 0 的字符。vector
> 是一个字符向量,而std::vector
是一个 C 风格字符串向量——这是非常不同的东西。更新。正如OP想要的那样,我给出了如何存储(在向量中)以null结尾的字符串(其中一些是空值)的想法。
选项 1:假设我们有
vector c_strings;
。然后,我们定义一个函数来存储字符串 pi。由于我们需要区分空字符串和空 char*,因此引入了很多复杂性。我们选择一个在我们的使用中不会出现的分隔字符。假设这是“~”字符。您仍然需要对上面
new[]
分配的内存调用delete[]
。所有这些复杂性都可以通过使用string
类来解决。我很少在 C++ 中使用char*
。选项 2:您可以使用
vector >
。然后'~'可以替换为空的boost::Optional,其他部分与选项1相同。但是这种情况下的内存占用会更高。NULL is just 0. A pointer with value 0 has a meaning. But a char with value 0 has a different meaning. It is used as a delimiter to show the end of a string. Therefore, if you use
std::vector<char>
andpush_back
0, the vector will contain a character with value 0.vector<char>
is a vector of characters, whilestd::vector<char*>
is a vector of C-style strings -- very different things.Update. As the OP wants, I am giving an idea of how to store (in a vector) null terminated strings some of which are nulls.
Option 1: Suppose we have
vector<char> c_strings;
. Then, we define a function to store a string pi. A lot of complexity is introduced since we need to distinguish between an empty string and a null char*. We select a delimiting character that does not occur in our usage. Suppose this is the '~' character.You still need to call
delete[]
on the memory allocated bynew[]
above. All this complexity is taken care of by using thestring
class. I very rarely usechar*
in C++.Option 2: You could use
vector<boost::optional<char> >
. Then the '~' can be replaced by an empty boost::optional, but other other parts are the same as option 1. But the memory usage in this case would be higher.