链式 strsep 给出分段错误 - C
Chained strsep gives segmentation fault - C
我正在尝试创建一个字符串数组,以准备将它们显示在 table。
所以我有一个函数 returns 一个缓冲区字符串,其中包含一些已扫描的 wifi 接入点列表,我正在使用 strsep
将其拆分为 "\n"
然后再次 "\t"
.
循环运行良好,直到到达末尾,当评估 while
参数 ((line = strsep(&buf, "\n")))
时,它给出 SEGFAULT
.
每个@Jabberwocky 要求的简短说明性示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int
wap_scan_count_lines(char* wap_scan)
{
int line_amount = 0;
char *scan = wap_scan;
while(*scan)
{
if ('\n' == *scan){
line_amount++;
}
scan++;
}
return line_amount;
}
int main() {
char ***scan_result, *line=NULL, *item=NULL, *scan=NULL;
scan = strdup("bssid / frequency / signal level / flags / ssid\n"
"a8:6a:bb:e2:d6:ef 5785 -47 [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS] Fibertel WiFi114 5.8GHz");
int wap_scan_size = wap_scan_count_lines(scan);
scan_result = malloc(wap_scan_size * sizeof(**scan_result));
int i = 0;
int item_len = sizeof (*scan_result);
while((line = strsep(&scan, "\n")) != NULL ) {
if(i==0){
i++;
continue;
}
char **scan_line = calloc(5, item_len);
int j = 0;
while ((item = strsep(&line, "\t")) != NULL) {
printf("%s\n", item);
scan_line[j++] = strdup(item);
}
scan_result[i++] = scan_line;
}
return 0;
}
给我问题的真正函数:
char *** wifi_client_get_wap_list(int *len)
{
char ***scan_result;
char *buf, *buf_free, *cmd, *line, *item;
int ret, items_len;
cmd = strdup("SCAN");
ret = wpa_ctrl_command(cmd, NULL);
if (ret < 0) goto error;
cmd = strdup("SCAN_RESULTS");
ret = wpa_ctrl_command(cmd, &buf); //RETURNS A STRING ON BUF ALLOCATED BY STRDUP
if (ret < 0){
free(buf);
goto error;
}
*len = wap_scan_count_lines(buf); //NUMBER OF LINES IN THE SCAN RESULT
scan_result = calloc(*len, sizeof(**scan_result));
int i = 0, j;
buf_free = buf;
items_len = sizeof (*scan_result);
while ((line = strsep(&buf, "\n"))){ //THIS GIVES THE SEGFAULT AT THE END
// SKIP FIRST LINE WITH HEADERS
if (i==0){
i++;
continue;
}
//if (strcmp(line, "") == 0) {
// break;
//}
//EACH LINE HAS 5 VALUES (bssid, freq, level,flags,ssid)
char **scan_line = calloc(5, items_len);
j = 0;
printf("INNER STEPS:\n");
while((item = strsep(&line, "\t"))){
*(scan_line + j) = strdup(item);
printf("%d ", j);
j++;
}
*(scan_result + i) = scan_line;
printf("\nSTEP: %d\n", i);
i++;
}
free(buf_free);
free(cmd);
return scan_result;
error:
// @TODO: Handle error
if (ret == -2) {
printf("'%s' command timed out.\n", cmd);
} else if (ret < 0) {
printf("'%s' command failed.\n", cmd);
}
free(cmd);
return NULL;
}
基于 https://man7.org/linux/man-pages/man3/strsep.3.html 问题是循环将 运行 比你想要的多一次,导致 scan_result溢出。
文档的相关部分是:
The strsep() function returns a pointer to the token, that is, it
returns the original value of *stringp.
和
If *stringp is NULL, the strsep() function returns NULL and does
nothing else. Otherwise, this function finds the first token in
the string *stringp, that is delimited by one of the bytes in the
string delim. This token is terminated by overwriting the
delimiter with a null byte ('[=11=]'), and *stringp is updated to
point past the token. In case no delimiter was found, the token
is taken to be the entire string *stringp, and *stringp is made
NULL.
在 wap_scan_count_lines 中,您计算以 '\n' 结尾的行数。
在接下来的两行中,您根据以'\n'结尾的行数分配内存来保存结果。
int wap_scan_size = wap_scan_count_lines(scan);
scan_result = malloc(wap_scan_size * sizeof(**scan_result));
但是,上面引用的 strsep() 的文档暗示在您的简化示例中,第一个 wap_scan_size 次 strsep被调用,在调用结束时结果不会为 NULL,并且 scan 不会在调用期间设置为 NULL。下次调用时,scan 将在调用期间设置为 NULL,但结果不会为 NULL。这意味着循环体将被执行 wap_scan_size + 1 次,导致写入超过 scan_result.
至少有两个可能的修复方法,具体取决于您是否真的想处理输入末尾未被“\n”终止的任何行。
如果你确实需要处理这样的行,这对我来说似乎更强大,特别是考虑到你的简化示例以这样的行结尾,只需在 scan_result[ 中分配一个额外的条目=46=]:
scan_result = malloc((wap_scan_size + 1) * sizeof(**scan_result));
如果您确定不需要处理这些行,但我觉得这不正确,请更改:
while((line = strsep(&scan, "\n")) != NULL ) {
到
for(line = strsep(&scan, "\n"); scan != NULL; line = strsep(&scan, "\n") ) {
我正在尝试创建一个字符串数组,以准备将它们显示在 table。
所以我有一个函数 returns 一个缓冲区字符串,其中包含一些已扫描的 wifi 接入点列表,我正在使用 strsep
将其拆分为 "\n"
然后再次 "\t"
.
循环运行良好,直到到达末尾,当评估 while
参数 ((line = strsep(&buf, "\n")))
时,它给出 SEGFAULT
.
每个@Jabberwocky 要求的简短说明性示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int
wap_scan_count_lines(char* wap_scan)
{
int line_amount = 0;
char *scan = wap_scan;
while(*scan)
{
if ('\n' == *scan){
line_amount++;
}
scan++;
}
return line_amount;
}
int main() {
char ***scan_result, *line=NULL, *item=NULL, *scan=NULL;
scan = strdup("bssid / frequency / signal level / flags / ssid\n"
"a8:6a:bb:e2:d6:ef 5785 -47 [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS] Fibertel WiFi114 5.8GHz");
int wap_scan_size = wap_scan_count_lines(scan);
scan_result = malloc(wap_scan_size * sizeof(**scan_result));
int i = 0;
int item_len = sizeof (*scan_result);
while((line = strsep(&scan, "\n")) != NULL ) {
if(i==0){
i++;
continue;
}
char **scan_line = calloc(5, item_len);
int j = 0;
while ((item = strsep(&line, "\t")) != NULL) {
printf("%s\n", item);
scan_line[j++] = strdup(item);
}
scan_result[i++] = scan_line;
}
return 0;
}
给我问题的真正函数:
char *** wifi_client_get_wap_list(int *len)
{
char ***scan_result;
char *buf, *buf_free, *cmd, *line, *item;
int ret, items_len;
cmd = strdup("SCAN");
ret = wpa_ctrl_command(cmd, NULL);
if (ret < 0) goto error;
cmd = strdup("SCAN_RESULTS");
ret = wpa_ctrl_command(cmd, &buf); //RETURNS A STRING ON BUF ALLOCATED BY STRDUP
if (ret < 0){
free(buf);
goto error;
}
*len = wap_scan_count_lines(buf); //NUMBER OF LINES IN THE SCAN RESULT
scan_result = calloc(*len, sizeof(**scan_result));
int i = 0, j;
buf_free = buf;
items_len = sizeof (*scan_result);
while ((line = strsep(&buf, "\n"))){ //THIS GIVES THE SEGFAULT AT THE END
// SKIP FIRST LINE WITH HEADERS
if (i==0){
i++;
continue;
}
//if (strcmp(line, "") == 0) {
// break;
//}
//EACH LINE HAS 5 VALUES (bssid, freq, level,flags,ssid)
char **scan_line = calloc(5, items_len);
j = 0;
printf("INNER STEPS:\n");
while((item = strsep(&line, "\t"))){
*(scan_line + j) = strdup(item);
printf("%d ", j);
j++;
}
*(scan_result + i) = scan_line;
printf("\nSTEP: %d\n", i);
i++;
}
free(buf_free);
free(cmd);
return scan_result;
error:
// @TODO: Handle error
if (ret == -2) {
printf("'%s' command timed out.\n", cmd);
} else if (ret < 0) {
printf("'%s' command failed.\n", cmd);
}
free(cmd);
return NULL;
}
基于 https://man7.org/linux/man-pages/man3/strsep.3.html 问题是循环将 运行 比你想要的多一次,导致 scan_result溢出。
文档的相关部分是:
The strsep() function returns a pointer to the token, that is, it
returns the original value of *stringp.
和
If *stringp is NULL, the strsep() function returns NULL and does
nothing else. Otherwise, this function finds the first token in
the string *stringp, that is delimited by one of the bytes in the
string delim. This token is terminated by overwriting the
delimiter with a null byte ('[=11=]'), and *stringp is updated to
point past the token. In case no delimiter was found, the token
is taken to be the entire string *stringp, and *stringp is made
NULL.
在 wap_scan_count_lines 中,您计算以 '\n' 结尾的行数。
在接下来的两行中,您根据以'\n'结尾的行数分配内存来保存结果。
int wap_scan_size = wap_scan_count_lines(scan);
scan_result = malloc(wap_scan_size * sizeof(**scan_result));
但是,上面引用的 strsep() 的文档暗示在您的简化示例中,第一个 wap_scan_size 次 strsep被调用,在调用结束时结果不会为 NULL,并且 scan 不会在调用期间设置为 NULL。下次调用时,scan 将在调用期间设置为 NULL,但结果不会为 NULL。这意味着循环体将被执行 wap_scan_size + 1 次,导致写入超过 scan_result.
至少有两个可能的修复方法,具体取决于您是否真的想处理输入末尾未被“\n”终止的任何行。
如果你确实需要处理这样的行,这对我来说似乎更强大,特别是考虑到你的简化示例以这样的行结尾,只需在 scan_result[ 中分配一个额外的条目=46=]:
scan_result = malloc((wap_scan_size + 1) * sizeof(**scan_result));
如果您确定不需要处理这些行,但我觉得这不正确,请更改:
while((line = strsep(&scan, "\n")) != NULL ) {
到
for(line = strsep(&scan, "\n"); scan != NULL; line = strsep(&scan, "\n") ) {