当大小未知时,通过引用将 char 数组传递给函数
Passing char array to a function by reference when the size is not known
我正在学习指针和字符数组,想知道您是否可以帮助我在这里找到最佳解决方案。我想避免使用 malloc,因此我选择通过引用将一个 char 数组传递给一个函数,其中值将被填充。
在我的 main.c
char saved_networks[100]; // create an array to save data
readFile123(SPIFFS, "/wifi.txt",saved_networks);
Serial.print("saved networks=");
Serial.println(saved_networks);
和函数:
void readFile123(fs::FS &fs, const char *path, char* return_data)
{
int n=0;
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if (!file || file.isDirectory())
{
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while (file.available())
{
char c = file.read();
delayMicroseconds(100);
Serial.print(c);
//strcat(return_data, &c); //returns meditation error
return_data[n]=c;
n=n+1;
}
file.close();
}
在上面的程序中,我创建了一个大小为 100 的字符数组并将其传递给函数。在函数内部,我读取 SPIFFS 文件系统中的数据,然后将我在其中找到的任何字符串赋给 char 数组。上面的代码有效,但我有 3 个问题:
1. 为什么我不能使用strcat(return_data, &c);
导致 cpu 崩溃和 return 错误:
Stack smashing protect failure!
abort() was called at PC 0x40137793 on core 1
ELF file SHA256: 0000000000000000
2. 为什么我不能如下声明我的字符数组:char* saved_networks;
。如果我这样做,我的微控制器将崩溃并 return 一个错误:
Read from file: TGuru Meditation Error: Core 1 panic'ed (StoreProhibited). Exception was unhandled
3.解决这个问题的最优方法是什么?因为我不知道我从 SPIFFS 读取的数据的最大大小是多少,所以简单地声明它的大小为 100 可能是不够的。有没有办法动态声明它?我假设唯一的方法是使用 malloc?是真的吗?
strcat(return_data, &c)
是一个 <string>
函数,因此,它需要实际的字符串而不是字符数组。
在您的示例中,您传递了一个 char 的地址,它可以解释为大小为 1 的 char 数组。
有什么区别?
好吧,字符串是以 null 结尾的 char 数组,这意味着它们的最后一个有效元素是 '[=14=]'
,那个 char 之后的所有内容都被那些 str
函数忽略。
char* saved_networks;
声明了一个可以存储char
类型地址的变量,你还是要分配space! space 的地址将存储在 saved_networks
.
中
你可以先看看文件有多大再看。或者您可以逐步阅读它。
由于您使用的是 C++
,因此您也可以使用 std::string
编辑:当您传递数组名称时,它已经是一个引用,所以我想说您已经正确传递了它,只是需要注意不要超过 space已分配(在本例中为 100 个字符)。
为了更清楚,让我给你举几个例子 syntatic sugar:
char saved_networks[100];
saved_networks == &saved_networks[0]; // true
saved_networks[0] == *saved_networks; // true
saved_networks[50] == *(saved_networks + 50); // true
&saved_networks[50] == saved_networks + 50; // true
+50
取决于数组类型:在本例中它表示 50 个字节,因为每个字符都是 1 个字节。
编辑 2:
"h"
实际上是 more similar to:
char const arr[2] = {'h', '[=11=]'};
这意味着 "
用于字符串而 '
用于字符!
这很重要,因为 str
函数期望字符串以 null 终止,否则无限循环将导致无效的内存访问。
我认为这就是您所缺少的,现在您将能够更好地理解我的第一点。
传递数组的长度:
size_t len = sizeof(saved_networks)/sizeof(*saved_networks);
char *saved_networks = readFile123(SPIFFS, "/wifi.txt",saved_networks, &len);
然后确保不超过长度:
char *readFile123(fs::FS &fs, const char *path, size_t *lenp)
{
size_t chunksize = *lenp; // You can pass in chunksize you want to use
size_t n = 0;
size_t chunk_len = 0;
char *return_data = malloc(chunksize);
return_data[0]=0;
*lenp = 0;
...
while (file.available())
{
char c = file.read();
delayMicroseconds(100);
Serial.print(c);
return_data[n]=c;
n=n+1;
chunk_len++;
if (chunk_len == chunksize-1)
{
return_data = realloc(return_data, n+chunksize);
chunk_len = 0;
}
}
return_data[n]=0;
*lenp = n;
return return_data;
}
我正在学习指针和字符数组,想知道您是否可以帮助我在这里找到最佳解决方案。我想避免使用 malloc,因此我选择通过引用将一个 char 数组传递给一个函数,其中值将被填充。 在我的 main.c
char saved_networks[100]; // create an array to save data
readFile123(SPIFFS, "/wifi.txt",saved_networks);
Serial.print("saved networks=");
Serial.println(saved_networks);
和函数:
void readFile123(fs::FS &fs, const char *path, char* return_data)
{
int n=0;
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if (!file || file.isDirectory())
{
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while (file.available())
{
char c = file.read();
delayMicroseconds(100);
Serial.print(c);
//strcat(return_data, &c); //returns meditation error
return_data[n]=c;
n=n+1;
}
file.close();
}
在上面的程序中,我创建了一个大小为 100 的字符数组并将其传递给函数。在函数内部,我读取 SPIFFS 文件系统中的数据,然后将我在其中找到的任何字符串赋给 char 数组。上面的代码有效,但我有 3 个问题:
1. 为什么我不能使用strcat(return_data, &c);
导致 cpu 崩溃和 return 错误:
Stack smashing protect failure!
abort() was called at PC 0x40137793 on core 1
ELF file SHA256: 0000000000000000
2. 为什么我不能如下声明我的字符数组:char* saved_networks;
。如果我这样做,我的微控制器将崩溃并 return 一个错误:
Read from file: TGuru Meditation Error: Core 1 panic'ed (StoreProhibited). Exception was unhandled
3.解决这个问题的最优方法是什么?因为我不知道我从 SPIFFS 读取的数据的最大大小是多少,所以简单地声明它的大小为 100 可能是不够的。有没有办法动态声明它?我假设唯一的方法是使用 malloc?是真的吗?
strcat(return_data, &c)
是一个<string>
函数,因此,它需要实际的字符串而不是字符数组。
在您的示例中,您传递了一个 char 的地址,它可以解释为大小为 1 的 char 数组。 有什么区别?
好吧,字符串是以 null 结尾的 char 数组,这意味着它们的最后一个有效元素是'[=14=]'
,那个 char 之后的所有内容都被那些str
函数忽略。
中char* saved_networks;
声明了一个可以存储char
类型地址的变量,你还是要分配space! space 的地址将存储在saved_networks
.你可以先看看文件有多大再看。或者您可以逐步阅读它。 由于您使用的是
C++
,因此您也可以使用 std::string
编辑:当您传递数组名称时,它已经是一个引用,所以我想说您已经正确传递了它,只是需要注意不要超过 space已分配(在本例中为 100 个字符)。
为了更清楚,让我给你举几个例子 syntatic sugar:
char saved_networks[100];
saved_networks == &saved_networks[0]; // true
saved_networks[0] == *saved_networks; // true
saved_networks[50] == *(saved_networks + 50); // true
&saved_networks[50] == saved_networks + 50; // true
+50
取决于数组类型:在本例中它表示 50 个字节,因为每个字符都是 1 个字节。
编辑 2:
"h"
实际上是 more similar to:
char const arr[2] = {'h', '[=11=]'};
这意味着 "
用于字符串而 '
用于字符!
这很重要,因为 str
函数期望字符串以 null 终止,否则无限循环将导致无效的内存访问。
我认为这就是您所缺少的,现在您将能够更好地理解我的第一点。
传递数组的长度:
size_t len = sizeof(saved_networks)/sizeof(*saved_networks);
char *saved_networks = readFile123(SPIFFS, "/wifi.txt",saved_networks, &len);
然后确保不超过长度:
char *readFile123(fs::FS &fs, const char *path, size_t *lenp)
{
size_t chunksize = *lenp; // You can pass in chunksize you want to use
size_t n = 0;
size_t chunk_len = 0;
char *return_data = malloc(chunksize);
return_data[0]=0;
*lenp = 0;
...
while (file.available())
{
char c = file.read();
delayMicroseconds(100);
Serial.print(c);
return_data[n]=c;
n=n+1;
chunk_len++;
if (chunk_len == chunksize-1)
{
return_data = realloc(return_data, n+chunksize);
chunk_len = 0;
}
}
return_data[n]=0;
*lenp = n;
return return_data;
}