Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
堆栈上的字符串-c中没有清除的临时字符串_C_String_Stack_Allocation - Fatal编程技术网

堆栈上的字符串-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

有没有更好的方法在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 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,而不会淹没堆栈