填补字符串留在C烦恼

时间:2010-12-04 22:51:35

标签: c string pointers padding

我想创建一个字符串填充函数,用于使用零填充左边填充,填充到定义的字节大小。我首先尝试使用printf,但是不允许对字符串进行零填充,并且不灵活。

我提出了以下功能:

char * strpadleft(char * string, char pad, size_t bytes) {
 size_t ssize = strlen(string);
 size_t bits = bytes * 8;                            
 char *padded = (char *) malloc(bits + 1); /* Bit size + null terminator */
 memset(padded, pad, bits);                /* Fill contents with zeros, leave last null terminator*/
 padded -= ssize + 1;                      /* Rewind back to offset*/
 strncpy(padded, string, ssize);           /* Replace for example bits 16->32 with representation*/
 return padded;
}

/*Example: strpadleft("0100100001", '0', 4); */

现在很遗憾,这只返回未填充的字符串(例如0100100001)。我的指针算法是错误的,我是否复制到了错误的位置,或者是否有其他我错过了不能让它工作的东西?

3 个答案:

答案 0 :(得分:3)

以下是使用示例调用strpadleft(“0100100001”,“0”,4)进行的分解。

ssize设置为10

位设置为32

填充指向分配的33字节内存区域。

以下是已分配内存的简单/粗略表示:

   ..............................................
ma 0000000000000000000000000000000000000000000000
ed xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
md 0000000000000000111111111111111222222222222222
yr 0123456789ABCDEF123456789ABCDEF123456789ABCDEF
              |                               |
              |                               padded allocation end
              padded allocation start

假设padded示例保存地址0x0B。

然后,

memset将已分配内存的所有字节设置为填充字符“0”。

   ...........00000000000000000000000000000000...
ma 0000000000000000000000000000000000000000000000
ed xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
md 0000000000000000111111111111111222222222222222
yr 0123456789ABCDEF123456789ABCDEF123456789ABCDEF
              |                               |
              |                               "padded" allocation end
              "padded" allocatoin start

然后从填充指针中减去11,填充现在保存地址0x00。

(这是你逻辑中的错误,你想增加指针而不是递减。你也像其他人所指出的那样,不想修改填充来做这个。改为使用temp变量,或者确保在执行字符串复制后重新填充。)

   0100100001n00000000000000000000000000000000... (Note: 'n' represents the null character here)
ma 0000000000000000000000000000000000000000000000
ed xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
md 0000000000000000111111111111111222222222222222
yr 0123456789ABCDEF123456789ABCDEF123456789ABCDEF
   |          |                               |
   |          |                               "padded" allocation end
   |          "padded" allocatoin start
   "padded" now points here 

然后你将返回地址填充点,你可以看到点到原始字符串的开头。

除此之外,你还没有做你想要的事情,你还可以通过在内存分配范围之外写入来破坏内存。

我建议您使用您选择的调试器,并尝试逐步查看关键变量以解决这些问题。

答案 1 :(得分:2)

存在重大误解和其他一些问题:

  • memset()不会更改padded

也就是说,函数中的变量没有改变; memset()只设置padded指向的数据。

因此,声称的“重置”操作padded -= ssize + 1通过访问您未分配的内存来调用未定义的行为。

使用:

strcpy(padded + bits - ssize, string);

而不是两行:

padded -= ssize + 1;
strncpy(padded, string, ssize);

使用strcpy()是安全的,因为您知道所有尺寸。

请注意malloc()不返回初始化数据,不能保证最后分配的字节为零。您必须使用calloc()

请注意,memset()操作不会终止字符串。

请注意,矛盾的是,使用strncpy()也不能保证空终止,即使你的起始位置正确,也不会使你的字符串终止。相比之下,使用strcpy()确保空终止。

工作代码

请注意修改后的界面 - 使用const char *作为第一个参数。 (static只是获取在我的默认编译标志下编译的代码而没有事先声明函数的投诉。当然,你不会将它用于头文件中声明的库函数。)

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static char *strpadleft(const char * string, char pad, size_t bytes)
{
    size_t ssize = strlen(string);
    size_t bits = bytes * 8;
    char *padded = (char *) malloc(bits + 1);
    assert(ssize < bits);
    memset(padded, pad, bits - ssize);
    strcpy(padded + bits - ssize, string);
    return padded;
}

int main(void)
{
    const char *data = "0100100001";
    char *pad = strpadleft(data, '0', 4);
    printf("Data: <<%s>> padded <<%s>> (%d)\n", data, pad, (int)strlen(pad));
    free(pad);
    return(0);
}

评论

如果ssize > bits(提示:assert()不正确),您确实需要确定适当的行为。但最有可能的是,你只需复制原始字符串。注意:返回指向原始字符串的指针,绝对不是可以接受的。该函数返回一个指向必须由应用程序释放的字符串的指针;因此,您必须始终返回已分配的字符串。否则,您的功能将无法使用;代码必须检查返回值是否与参数相同,如果相同,则不释放返回值。呸!

准固定代码

证明原始代码中缺少空终止:

static char * strpadleft(const char * string, char pad, size_t bytes)
{
    size_t ssize = strlen(string);
    size_t bits = bytes * 8;
    char *padded = (char *) malloc(bits + 1);
    padded[bits] = 'X';  // Overwrite last allocated byte
    memset(padded, pad, bits);
    strncpy(padded + bits - ssize, string, ssize);
    return padded;
}

使用与以前相同的测试程序,并依赖于未定义的行为(不能保证X之后的字节是空字节),我得到了:

Data: <<0100100001>> padded <<00000000000000000000000100100001X>> (33)

请注意strncpy()不会覆盖'X'!您可以使用ssize + 1解决此问题,但为什么不使用strcpy() ......如前所述......

答案 2 :(得分:1)

更改行:

padded -= ssize + 1;
strncpy(padded, string, ssize);           /* Replace for example bits 16->32 with representation*/

char *data = padded + (bits - ssize);
strncpy(data , string, ssize);           /* Replace for example bits 16->32 with representation*/
padded [bits] = '\0';

不要更改填充,因为你要返回该值,原因是因为创建了变量数据,并且phihag表示memset不会更改填充的地址。