堆栈上的字符串-c中没有清除的临时字符串
有没有更好的方法在C中临时分配长度未知的字符串,而不需要清理堆栈上的字符串-c中没有清除的临时字符串,c,string,stack,allocation,C,String,Stack,Allocation,有没有更好的方法在C中临时分配长度未知的字符串,而不需要清理 // OLD // #define stackdup(s) \ // memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s)) #define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments // stackndup and stack
// OLD
// #define stackdup(s) \
// memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s))
#define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments
// stackndup and stackmiddup can't use strcpy because they need memset 0 ...
#define stackndup(s,n) \
memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), \
s, n > strlen(s) ? strlen(s) : n )
#define stackmiddup(s,pos,n) \
memcpy(memset(_alloca(strlen(&s[pos]) + 1), 0, strlen(&s[pos]) + 1), \
&s[pos], n > strlen(&s[pos]) ? strlen(&s[pos])) )
int main ()
{
const char *address = "123 Main Street";
const char *copy_address = stackdup (address); // "123 Main Street"
const char *address_123 = stackndup (address, 8); // "123 Main"
const char *address_123x = stackndup (address, 55); // "123 Main Street"
const char *address_main = stackmiddup (address, 4, 4); // "Main"
...
}
我目前使用的是以下函数,它使用alloca/\u alloca或插入编译器喜欢的函数名
// OLD
// #define stackdup(s) \
// memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s))
#define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments
// stackndup and stackmiddup can't use strcpy because they need memset 0 ...
#define stackndup(s,n) \
memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), \
s, n > strlen(s) ? strlen(s) : n )
#define stackmiddup(s,pos,n) \
memcpy(memset(_alloca(strlen(&s[pos]) + 1), 0, strlen(&s[pos]) + 1), \
&s[pos], n > strlen(&s[pos]) ? strlen(&s[pos])) )
int main ()
{
const char *address = "123 Main Street";
const char *copy_address = stackdup (address); // "123 Main Street"
const char *address_123 = stackndup (address, 8); // "123 Main"
const char *address_123x = stackndup (address, 55); // "123 Main Street"
const char *address_main = stackmiddup (address, 4, 4); // "Main"
...
}
利用memcpy和memset返回dest的方式,将缓冲区格式化一个额外字节以提供空终止
// OLD
// #define stackdup(s) \
// memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s))
#define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments
// stackndup and stackmiddup can't use strcpy because they need memset 0 ...
#define stackndup(s,n) \
memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), \
s, n > strlen(s) ? strlen(s) : n )
#define stackmiddup(s,pos,n) \
memcpy(memset(_alloca(strlen(&s[pos]) + 1), 0, strlen(&s[pos]) + 1), \
&s[pos], n > strlen(&s[pos]) ? strlen(&s[pos])) )
int main ()
{
const char *address = "123 Main Street";
const char *copy_address = stackdup (address); // "123 Main Street"
const char *address_123 = stackndup (address, 8); // "123 Main"
const char *address_123x = stackndup (address, 55); // "123 Main Street"
const char *address_main = stackmiddup (address, 4, 4); // "Main"
...
}
不能明显地使用它,因为它会在堆栈上分配一次。
< P>如果C++不是一个选项,自动清除是目标,那么你可以尝试提供C++风格的智能指针,并在内存堆上进行自动管理。 < >用C99编译器,可以动态地调整本地数组:// OLD
// #define stackdup(s) \
// memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s))
#define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments
// stackndup and stackmiddup can't use strcpy because they need memset 0 ...
#define stackndup(s,n) \
memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), \
s, n > strlen(s) ? strlen(s) : n )
#define stackmiddup(s,pos,n) \
memcpy(memset(_alloca(strlen(&s[pos]) + 1), 0, strlen(&s[pos]) + 1), \
&s[pos], n > strlen(&s[pos]) ? strlen(&s[pos])) )
int main ()
{
const char *address = "123 Main Street";
const char *copy_address = stackdup (address); // "123 Main Street"
const char *address_123 = stackndup (address, 8); // "123 Main"
const char *address_123x = stackndup (address, 55); // "123 Main Street"
const char *address_main = stackmiddup (address, 4, 4); // "Main"
...
}
void demo (const char * original)
{
char copy[strlen (original) + 1];
strcpy (copy, original);
...
}
这与alloca的工作原理相同,但它更干净(更)便携。如果长度未知且可能很大,请不要因为堆栈溢出而使用alloca,而是使用malloc&
free
,或者,在本主题中,有一些用于垃圾收集的库,但是通过使用它们,性能可能会下降
// OLD
// #define stackdup(s) \
// memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s))
#define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments
// stackndup and stackmiddup can't use strcpy because they need memset 0 ...
#define stackndup(s,n) \
memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), \
s, n > strlen(s) ? strlen(s) : n )
#define stackmiddup(s,pos,n) \
memcpy(memset(_alloca(strlen(&s[pos]) + 1), 0, strlen(&s[pos]) + 1), \
&s[pos], n > strlen(&s[pos]) ? strlen(&s[pos])) )
int main ()
{
const char *address = "123 Main Street";
const char *copy_address = stackdup (address); // "123 Main Street"
const char *address_123 = stackndup (address, 8); // "123 Main"
const char *address_123x = stackndup (address, 55); // "123 Main Street"
const char *address_main = stackmiddup (address, 4, 4); // "Main"
...
}
如果可能,不要再次分配字符串。如果需要最大的性能,除了调用strlen()
之外,还可以传递它们的长度
// OLD
// #define stackdup(s) \
// memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s))
#define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments
// stackndup and stackmiddup can't use strcpy because they need memset 0 ...
#define stackndup(s,n) \
memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), \
s, n > strlen(s) ? strlen(s) : n )
#define stackmiddup(s,pos,n) \
memcpy(memset(_alloca(strlen(&s[pos]) + 1), 0, strlen(&s[pos]) + 1), \
&s[pos], n > strlen(&s[pos]) ? strlen(&s[pos])) )
int main ()
{
const char *address = "123 Main Street";
const char *copy_address = stackdup (address); // "123 Main Street"
const char *address_123 = stackndup (address, 8); // "123 Main"
const char *address_123x = stackndup (address, 55); // "123 Main Street"
const char *address_main = stackmiddup (address, 4, 4); // "Main"
...
}
例如,代替
// OLD
// #define stackdup(s) \
// memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s))
#define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments
// stackndup and stackmiddup can't use strcpy because they need memset 0 ...
#define stackndup(s,n) \
memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), \
s, n > strlen(s) ? strlen(s) : n )
#define stackmiddup(s,pos,n) \
memcpy(memset(_alloca(strlen(&s[pos]) + 1), 0, strlen(&s[pos]) + 1), \
&s[pos], n > strlen(&s[pos]) ? strlen(&s[pos])) )
int main ()
{
const char *address = "123 Main Street";
const char *copy_address = stackdup (address); // "123 Main Street"
const char *address_123 = stackndup (address, 8); // "123 Main"
const char *address_123x = stackndup (address, 55); // "123 Main Street"
const char *address_main = stackmiddup (address, 4, 4); // "Main"
...
}
const char *address = "123 Main Street";
const char *copy_address = stackdup (address);
使用
// OLD
// #define stackdup(s) \
// memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s))
#define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments
// stackndup and stackmiddup can't use strcpy because they need memset 0 ...
#define stackndup(s,n) \
memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), \
s, n > strlen(s) ? strlen(s) : n )
#define stackmiddup(s,pos,n) \
memcpy(memset(_alloca(strlen(&s[pos]) + 1), 0, strlen(&s[pos]) + 1), \
&s[pos], n > strlen(&s[pos]) ? strlen(&s[pos])) )
int main ()
{
const char *address = "123 Main Street";
const char *copy_address = stackdup (address); // "123 Main Street"
const char *address_123 = stackndup (address, 8); // "123 Main"
const char *address_123x = stackndup (address, 55); // "123 Main Street"
const char *address_main = stackmiddup (address, 4, 4); // "Main"
...
}
在第二种情况下,地址是可写的,而在第一种情况下,地址不是可写的。通过这种方式,您可以使stackndup
和stackmiddup
更快—如果这些字符串在一行中逐个使用(例如,打印或写入它们,或者使用静态数组复制到结构,如struct{char street[32];}
),您只需保存索引(或更好的指针)使用原始字符并在其中写入零。请注意,您必须使用函数来恢复原始字符串-将原始字符设置回原来的位置
// OLD
// #define stackdup(s) \
// memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s))
#define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments
// stackndup and stackmiddup can't use strcpy because they need memset 0 ...
#define stackndup(s,n) \
memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), \
s, n > strlen(s) ? strlen(s) : n )
#define stackmiddup(s,pos,n) \
memcpy(memset(_alloca(strlen(&s[pos]) + 1), 0, strlen(&s[pos]) + 1), \
&s[pos], n > strlen(&s[pos]) ? strlen(&s[pos])) )
int main ()
{
const char *address = "123 Main Street";
const char *copy_address = stackdup (address); // "123 Main Street"
const char *address_123 = stackndup (address, 8); // "123 Main"
const char *address_123x = stackndup (address, 55); // "123 Main Street"
const char *address_main = stackmiddup (address, 4, 4); // "Main"
...
}
编辑
内存友好的剪切和子字符串函数(用于以null结尾的字符串)的作用与您的示例相同:
// OLD
// #define stackdup(s) \
// memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), s, strlen(s))
#define stackdup(s) strcpy(_alloca(strlen(s) + 1), s) // refined per comments
// stackndup and stackmiddup can't use strcpy because they need memset 0 ...
#define stackndup(s,n) \
memcpy(memset(_alloca(strlen(s) + 1), 0, strlen(s) + 1), \
s, n > strlen(s) ? strlen(s) : n )
#define stackmiddup(s,pos,n) \
memcpy(memset(_alloca(strlen(&s[pos]) + 1), 0, strlen(&s[pos]) + 1), \
&s[pos], n > strlen(&s[pos]) ? strlen(&s[pos])) )
int main ()
{
const char *address = "123 Main Street";
const char *copy_address = stackdup (address); // "123 Main Street"
const char *address_123 = stackndup (address, 8); // "123 Main"
const char *address_123x = stackndup (address, 55); // "123 Main Street"
const char *address_main = stackmiddup (address, 4, 4); // "Main"
...
}
#include <stdio.h>
#include <string.h>
/*
Macros
*/
#define plong long
#define istr_init(i) \
char* __ptr##i = NULL; \
char prev##i; \
#define istr_cut(i,s,n) \
(char*) s; \
if(n > s##_len) { \
(__ptr##i) = NULL; \
} else { \
__ptr##i = (s + n); \
prev##i = *(__ptr##i); \
*(__ptr##i) = 0; \
}
#define istr_substring(i,s,pos,n) \
(pos > s##_len) ? "" : (char*) ((__ptr##i) = (s + pos)); \
if(pos > s##_len) { \
(__ptr##i) = NULL; \
} else { \
if((pos + n) < s##_len) { \
(__ptr##i) += n; \
(prev##i) = *(__ptr##i); \
*(__ptr##i) = 0; \
} else { \
(__ptr##i) = NULL; \
} \
}
#define istr_back(i) \
if(__ptr##i) { \
*(__ptr##i) = (prev##i); \
(__ptr##i) = NULL; \
}
/*
Main
*/
;int main() {
{
istr_init(1); //Init - our ID=1
char* cur;
char address[] = "123 Main Street";
unsigned plong address_len = strlen(address); //<name>_len required
cur = istr_cut(1, address, 8);
printf(" address_123: [%s]\n", cur);
istr_back(1);
cur = istr_cut(1, address, 55);
printf(" address_123x: [%s]\n", cur);
istr_back(1);
cur = istr_substring(1, address, 4, 4);
printf(" address_main: [%s]\n", cur);
istr_back(1);
cur = istr_substring(1, address, 4, 55);
printf(" address_mainx: [%s]\n", cur);
istr_back(1);
cur = istr_substring(1, address, 55, 4);
printf(" address_null: [%s]\n", cur);
istr_back(1);
}
return 0;
}
您只想在全局范围内声明它?关于
char address[]=“123 main street”如何代码>?为什么你不能用它呢?我推荐charaddress_main[5];snprintf(主地址,主地址的大小,“%s”,地址+5)代码>。所有这些宏看起来都很可爱,但对于维护程序员来说,它们会让代码看起来很奇怪。如果你真的愿意,你可以将其包装在宏中。当然,另一个选择是首先不要这样做,并更改你正在调用的任何函数以获取指针和长度,而不是期望以null结尾的字符串只是一个警告。如果用户对字符串有控制权,则堆栈溢出并崩溃或者线程溢出堆栈并写入其他内存(可能是其他线程堆栈)相对来说是微不足道的。永远不要在你无法完全控制的长度上进行alloca。Alloca功能强大,但在某些情况下也非常危险。编译器可以选择安全地执行alloca,但据我所知,默认情况下没有编译器会这样做。我原则上同意,但Microsoft Visual Studio是C89,我希望它可以与任何主流编译器一起使用。“而且(更)可移植性”不太好。。。C11再次使VLA成为可选的。C11编译器可能无法处理VLA,因此只有在坚持使用C99兼容编译器的情况下,它才是可移植的。然而,VLA将用循环中的字符串解决OP的问题,因为它们在每次终止后都会被GC’ed,而不会淹没堆栈