我是一名 .NET 人员,正在深入研究 C++/微控制器领域。
以下是我正在尝试做的事情的模型。我有一个传入值的方法,并且根据该值我想返回一个不同的硬编码字符串数组。
当我单步执行此操作时,我的函数main()似乎可以工作,并且看起来我正在函数中返回正确的类型。我可以设置一个断点并查看files[0]是否是预期的字符串,files[1]是否是预期的字符串等。我可以单步执行循环并设置监视,files[i]然后我会看到适当的字符串。那里一切都很好。
那么两个问题:如何获取数组中有多少个元素?看了一百万个帖子,看来我做不到,对吧?我是否只需要一些在循环时需要检查的结束字符串(例如空字符串)?
其次,你会注意到我已经注释掉printf()了。当我启用该功能后,在单步执行后printf(),它会更改字符串的内容,但我不明白为什么要这样做。查看逐步执行之前/之后的图像以及手表的结果。我认为这可能是因为字符串没有以 a 隐式终止\0,但这没有效果。
#include <cstdlib>
#include <cstdio>
const char** GetSoundCategory(int category)
{
const char* FILES1[3] = {
"/myfile1.mp3",
"/this_is_my_file.mp3",
"/myfile9.mp3"
};
const char* FILES2[2] = {
"/I love S.E.mp3",
"/please_help_me.mp3"
};
const char** ptr = nullptr;
switch (category)
{
case 1:
ptr = FILES1;
break;
case 2:
ptr = FILES2;
break;
}
return ptr;
}
int main()
{
const char** files = GetSoundCategory(2);
constexpr int number_of_files = 3;
for (int i = 0; i < number_of_files; i++)
{
// printf("%s\n", files[i]);
}
}
Run Code Online (Sandbox Code Playgroud)
前printf:
后printf:
您的代码以两种不同的方式表现出未定义的行为。
GetSoundCategory()返回一个指向局部变量的指针,该局部变量在GetSoundCategory()退出时被释放,因此返回的指针处于悬空状态,在调用者有机会使用它之前指向无效内存。
由于您的数组不会更改,因此您可以将它们移动到全局内存或静态内存中,以便它们在GetSoundCategory()退出后保持活动状态,例如:
static const char* FILES1[3] = {
"/myfile1.mp3",
"/this_is_my_file.mp3",
"/myfile9.mp3"
};
static const char* FILES2[2] = {
"/I love S.E.mp3",
"/please_help_me.mp3"
};
const char** GetSoundCategory(int category)
{
...
}
Run Code Online (Sandbox Code Playgroud)
或者:
const char** GetSoundCategory(int category)
{
static const char* FILES1[3] = {
"/myfile1.mp3",
"/this_is_my_file.mp3",
"/myfile9.mp3"
};
static const char* FILES2[2] = {
"/I love S.E.mp3",
"/please_help_me.mp3"
};
...
}
Run Code Online (Sandbox Code Playgroud)
GetSoundCategory()您的编码方式main()无法知道返回的数组中实际有多少个字符串。因此,当 时category == 2,循环最终超出范围,因为数组中只有 2 个字符串,但循环迭代了 3 次。
要解决这个问题,您有几种选择。您可以:
以空值终止数组,例如:
const char** GetSoundCategory(int category)
{
static const char* FILES1[4] = {
"/myfile1.mp3",
"/this_is_my_file.mp3",
"/myfile9.mp3",
nullptr
};
static const char* FILES2[3] = {
"/I love S.E.mp3",
"/please_help_me.mp3",
nullptr
};
...
}
...
const char** files = GetSoundCategory(2);
for (int i = 0; files[i] != nullptr; i++)
{
printf("%s\n", files[i]);
}
Run Code Online (Sandbox Code Playgroud)
返回数组长度以及数组指针。您可以使用输出参数来做到这一点,例如:
const char** GetSoundCategory(int category, int *length)
{
...
*length = ...;
return ...;
}
...
int number_of_files;
const char** files = GetSoundCategory(2, &number_of_files);
Run Code Online (Sandbox Code Playgroud)
或者,返回一个struct包含数组指针和数组长度的简单值,例如:
struct filesArray {
const char** files;
int number_of_files;
};
filesArray GetSoundCategory(int category)
{
...
filesArray fa;
fa.files = ...;
fa.number_of_files = ...;
return fa;
}
...
filesArray fa = GetSoundCategory(2);
for (int i = 0; i < fa.number_of_files; i++)
{
printf("%s\n", fa.files[i]);
}
Run Code Online (Sandbox Code Playgroud)
话虽如此,您确实应该在代码中放弃旧的基于 C 的习惯用法,并采用更现代的 C++ 习惯用法,例如std::vector、std::array、std::string(_view)等,例如:
#include <iostream>
#include <vector>
#include <array>
#include <string_view>
std::vector<std::string_view> GetSoundCategory(int category)
{
static std::array<const char*, 3> FILES1 = {
"/myfile1.mp3",
"/this_is_my_file.mp3",
"/myfile9.mp3"
};
static std::array<const char*, 2> FILES2 = {
"/I love S.E.mp3",
"/please_help_me.mp3"
};
switch (category)
{
case 1:
return {FILES1.begin(), FILES1.end()};
case 2:
return {FILES2.begin(), FILES2.end()};
}
return {};
}
int main()
{
auto files = GetSoundCategory(2);
for (auto file : files)
{
std::cout << file << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)