我需要从不同长度的字符串中提取一个子字符串。我想避免使用malloc。
这安全吗?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
const char *PATTERN1 = "<Abcd.";
const char *PATTERN2 = ">";
const char *PATTERN3 = "<Fghi.";
char *begin, *end;
int len;
char result[50];
// lenght of toFind could be different i.e. "<Abcd.toGet>" or "<Abcd.toGettoGettoGet>" always less than 50
char *toFind[50] = {"<Abcd.toGettoGet>","<Abcd.toGettoGetoGet>","<Abcd.toGet>"};
int element = 3;
int i = 0;
for (i = 0; i < element ; i++) {
begin = strstr(toFind[i], PATTERN1);
printf("Begin: %s n", begin);
if (begin == NULL) {
perror("Null beginn");
}
begin += strlen(PATTERN1);
printf("Begin2: %s n", begin);
end = strstr(begin, PATTERN2);
printf("End: %s n", end);
if (end == NULL) {
perror("Null endn");
}
len = end - begin;
printf("Len: %d n", len);
strncpy(result, begin, len);
result[len] = ' ';
printf("Result = %sn",result);
sleep(5);
}
return 0;
}
我想知道这是否是一种正确而安全的方法,以避免分段错误或内存损坏/泄漏。特别是如何初始化它的开始和结束。
您需要解决一些问题。
- 不要只在
begin
或end
为NULL时继续
您应该在放置以下代码的位置添加一个else
部分。示例:
if (begin == NULL) {
perror("Null beginn");
} else {
begin += strlen(PATTERN1);
...
...
if (end == NULL) {
perror("Null endn");
} else {
len = end - begin;
...
...
}
}
- 超出范围写入
result
result
数组是固定大小的,但len
可以获得任何大小。因此,使用strncpy(result, begin, len);
不会保护您不受越界写入的影响。在使用strncpy
之前添加检查
- 如果
strstr
返回NULL,则不要打印字符串
即
begin = strstr(toFind[i], PATTERN1);
printf("Begin: %s n", begin); // Check for NULL **before** printing
不,太可怕了。
-
在检查NULL之前使用
strstr
的结果。这是一个bug。 -
你没有检查
len < sizeof(result)
,所以strncpy
是危险的。这是一个bug。如果
strncpy_s
既可用又实施良好,那么使用它会更安全:errno_t error = strncpy_s(result, sizeof(result), begin, len);
显然不是,所以你需要自己正确计算实际大小:
size_t copylen = min(sizeof(result)-1, len); strncpy(result, begin, copylen); result[copylen] = ' ';
(请注意,使用这种代码可以很容易地避免一个错误,不要只相信我的话:自己检查和测试(。
如果你想把它包装成一个函数,你不能使用本地数组变量并返回它。
在没有分配的情况下提取子字符串的唯一简单方法是实际返回(指针,长度(或(原始指针,偏移量,长度(元组。
否则,您需要调用方传入一个结果数组(以及正确的大小!(,这只会将分配推到其他地方。