将字符串复制到缓冲区

标签 c arrays copy pointers

我有一些代码在使用 sprintf 复制指向字符串的指针时会进行堆栈转储。我正在尝试将动物的内容复制到一个名为 output 的新指针数组中。但是,我得到了堆栈转储。

输出中应包含以下内容: 新动物兔子 新动物马 新动物驴

我以正确的方式解决这个问题吗?

非常感谢

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

void p_init(const char **animals, char **output);

int main(int argc, char **argv)
{
    char *animals[] = {"rabbit", "horse", "donkey", '\0'};  
    char **prt_animals = animals;
    char *output[sizeof(*animals)];

        /* print the contents here */
    while(*prt_animals)
    {
        printf("Animal: %s\n", *prt_animals++);
    }

        /* copy and update in the output buffer */
    p_init(*&animals, *&output);

    getchar();

    return 0;


void p_init(const char **animals, char **output)
{
    while(*animals)
    {
        sprintf(*output, "new animal %s", *animals); 
        *output++;
    }
}

最佳答案

数组animals 是一个指针数组。它不是某种大小的缓冲区数组。因此,如果你这样做了

sizeof(*animals)

您将获得该数组第一个元素的大小。相当于

sizeof(char*)

因为你的数组存储指针。因此,在读取的行中

char *output[sizeof(*animals)];

您在一个数组中分配了 4 个或 8 个指针(取决于您平台上指针的宽度。通常是 4 个或 8 个)。但这当然没有意义!您想要做的是创建一个与 animals 大小相同的指针数组。你必须先得到动物数组的总大小,然后除以一个元素的大小

char *output[sizeof(animals)/sizeof(*animals)];

现在,这就是您想要的。但是指针仍将具有不确定的值...接下来您使用 *&animals 传递数组(另一个相同)。为什么?您可以直接传递 animals。获取它的地址然后取消引用与一开始什么都不做是一样的。

然后在您调用的函数中,您将 animal 中的元素指向的字符串复制到某个不确定的目的地(记住 output 数组的元素 - 指针 -还有不确定的值。我们还没有分配它们!)。您首先必须分配适量的内存并使元素指向该内存。

while(*animals) {
        // now after this line, the pointer points to something sensible
        *output = malloc(sizeof("new animal ") + strlen(*animals));
        sprintf(*output, "new animal %s", *animals); 
        output++; // no need to dereference the result
        animals++; // don't forget to increment animals too!
}

加法,关于上面的sizeof

您必须确定一件重要的事情。这是我们计算尺寸的方式。无论您做什么,请确保您始终有足够的空间放置琴弦! C 字符串由字符和一个终止空字符组成,它标志着字符串的结尾。因此,*output 应该指向一个缓冲区,该缓冲区至少要包含用于“new animal”*animals 的空间。第一个包含 11 个字符。第二个取决于我们实际复制的内容 - 它的长度是 strlen 返回的内容。所以,我们总共需要

12 + strlen(*animals)

所有字符的空格,包括终止空值。现在,将该数字硬编码到您的代码中并不是一种好的风格。前缀可能会更改,您可能会忘记更新数字或误数一两个字符。这就是我们使用 sizeof 的原因,我们将其与我们想要添加的字符串文字一起提供。回想一下,sizeof 表达式的计算结果为其操作数的大小。您之前在 main 中使用它来获取数组的总大小。现在您将它用于字符串文字。所有字符串文字都是字符数组。字符串文字由您键入的字符组成, 空字符外。因此,以下条件成立,因为 strlen 计算 C 字符串的长度,并且不包括终止空字符到它的长度

// "abc" would have the type char[4] (array of 4 characters)
sizeof "..." == strlen("...") + 1

我们不必除以一个元素的大小,因为 sizeof char 无论如何都是一个,所以不会有什么区别。为什么我们使用 sizeof 而不是 strlen?因为它已经考虑了终止空字符,并且它在编译时进行评估。编译器可以逐字替换 sizeof 表达式返回的大小。

关于将字符串复制到缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/663064/

相关文章:

c - 使用二进制补码的按位减法溢出

linux - 在 Linux 上复制 N 天前的文件

javascript - Gulp 不会覆盖 JS 文件

vba - 使用单元格属性将范围从一个工作表复制到另一个工作表

c - 尝试在用户定义的函数中操作 char 数组的元素时收到错误

c - 在 C 中使用两个 fork() 时如何利用每个进程

c - 为什么要触发两次 SIGINT 才能按预期工作?

代码:: block 。 conio.h cprintf 不工作

c - 释放结构中的数组

python - numpy 数组上的高效行操作