【问题标题】:Python Generated String in CC语言中Python生成的字符串
【发布时间】:2017-04-14 03:37:15
【问题描述】:

我需要在 C 中生成以下字符串:

$(python -c "print('\x90' * a + 'blablabla' + '\x90' * b + 'h\xef\xff\xbf')")

其中 a 和 b 是任意整数,blablabla 表示任意字符串。我试图通过首先创建

char str1[size];

然后做:

for (int i = 0; i < a; i+=1) {

strcat(str1, "\x90");

}

接下来我再次使用strcat:

strcat(str1, "blablabla");

我再次运行循环,这次是 b 次,以连接下一个 b x90 字符。最后,我再次使用 strcat 如下:

strcat(str1, "h\xef\xff\xbf"); 

但是,这两个字符串不匹配。有没有更有效的方法在 C 中复制 python * 的行为?还是我错过了什么?

【问题讨论】:

  • 在这样的循环中使用 strcat 是二次的,正如我最喜欢的一篇博文(由 Stack Overflow 的创始人之一)所述:joelonsoftware.com/articles/fog0000000319.html 除了是一本好书,它可能会给你一些想法。

标签: python c arrays char strcat


【解决方案1】:
char str1[size];

即使您正确计算了尺寸,我还是建议您使用

char * str = malloc(size);

无论哪种方式,在您以一种或另一种方式获得字符串所需的内存后,您都必须先初始化它

str[0]=0;

如果您打算使用strcat

for (int i = 0; i < a; i+=1) {
    strcat(str1, "\x90");
}

这很有用,如果 "\x90" 实际上是一个字符串(即由多个字符组成的东西)并且该字符串是(很难给出一个硬边框,但大约 16 字节的东西是顶部) a 相当小[1]。在这里,正如John Coleman 已经建议的那样,memset 是一种更好的方法。

memset(str, '\x90', a);

因为您知道应该存储"blablabla" 的位置,所以只需使用strcpy 而不是strcat 将其存储在那里

// strcat(str1, "blablabla");
strcpy(str + a, "blablabla");

但是,您需要"blablabla" 之后的字符的地址(一种或另一种方式)。所以我什至不会那样做,而是这样:

const char * add_str = "blablabla";
size_t sl = strlen(add_str);
memcpy(str + a, add_str, sl);

然后,不要使用第二个循环,而是使用另一个 memset

memset(str + a + sl, '\x90', b);

最后但同样重要的是,strcpystrcat 更好(这里,memcpy 没有帮助):

strcpy(str + a + sl + b, "h\xef\xff\xbf");

但是你在开始时需要它的大小来计算大小,所以最好还是像 blablabla 字符串那样做(记住拖尾 '\0')。

最后,我会将所有这些代码放入这样的函数中:

char * gen_string(int a, int b) {
    const char * add_str_1 = "blablabla";
    size_t sl_1 = strlen(add_str_1);
    const char * add_str_2 = "h\xef\xff\xbf";
    size_t sl_2 = strlen(add_str_2);

    size_t size = a + sl_1 + b + sl_2 + 1;
    // The + 1 is important for the '\0' at the end

    char * str = malloc(size);
    if (!str) {
        return NULL;
    }
    memset(str, '\x90', a);
    memcpy(str + a, add_str_1, sl_1);
    memset(str + a + sl_1, '\x90', b);
    memcpy(str + a + sl_1 + b, add_str_2, sl_2);
    str[a + sl_1 + b + sl_2] = 0; // 0 is the same as '\0'

    return str;
}

记住free() gen_string 在某个时候的返回值。

如果memsetmemcpy 调用的列表变得更长,那么我建议这样做:

    char * ptr = str;
    memset(ptr, '\x90',    a   ); ptr += a;
    memcpy(ptr, add_str_1, sl_1); ptr += sl_1;
    memset(ptr, '\x90',    b   ); ptr += b;
    memcpy(ptr, add_str_2, sl_2); ptr += sl_2;
    *ptr = 0; // 0 is the same as '\0'

甚至可以为memsetmemcpy 创建一个宏:

#define MEMSET(c, l) do { memset(ptr, c, l); ptr += l; } while (0)
#define MEMCPY(s, l) do { memcpy(ptr, s, l); ptr += l; } while (0)

    char * ptr = str;
    MEMSET('\x90',    a   );
    MEMCPY(add_str_1, sl_1);
    MEMSET('\x90',    b   );
    MEMCPY(add_str_2, sl_2);
    *ptr = 0; // 0 is the same as '\0'

#undef MEMSET
#undef MEMCPY

关于为什么要按照我推荐的方式进行操作的理由,我建议您阅读博客文章 Back to Basics(由 Stack Overflow 的一位创始人撰写),这不仅是 John Coleman 最喜欢的博客文章,也是我最喜欢的博客文章.在那里您将了解到,在循环中使用 strcat 就像您第一次尝试它的方式一样具有二次运行时间,因此,为什么不按照您的方式使用它。

[1] 如果a 很大和/或需要重复的字符串很长,更好的解决方案是这样的:

const char * str_a = "\x90";
size_t sl_a = strlen(str_a);

char * ptr = str;
for (size_t i = 0; i < a; ++i) {
    strcpy(ptr, str_a);
    ptr += sl_a;
}
// then go on at address str + a * sl_a

【讨论】:

    【解决方案2】:

    对于单个 1 字节字符,您可以使用 memset 部分复制 Python 的 * 的行为:

    #include<stdio.h>
    #include<string.h>
    
    int main(void){
        char buffer[100];
    
        memset(buffer,'#',10);
        buffer[10] = '\0';
    
        printf("%s\n",buffer);
    
        memset(buffer, '*', 5);
        buffer[5] = '\0';
    
        printf("%s\n",buffer);
    
        return 0;
    }
    

    输出:

    ##########
    *****
    

    如需更稳健的解决方案,请参阅this

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-25
      • 1970-01-01
      • 1970-01-01
      • 2021-10-24
      • 2015-08-06
      • 1970-01-01
      相关资源
      最近更新 更多