为什么使用malloc创建的指针赋值会导致分段错误

为什么使用malloc创建的指针赋值会导致分段错误,c,pointers,C,Pointers,有人能解释一下为什么在这里使用malloc会导致mystrncat()中指定行出现seg故障吗?我的印象是,我可以跨不同的堆栈框架访问堆的元素。有什么资料可以让我更好地理解这个话题吗 多谢各位 编辑: 这是我的更新代码,仍然在这个位置 #include <stdio.h> #include <stdlib.h> #include <string.h> #define initial_malloc 20 char* mystrncat(char *dest,

有人能解释一下为什么在这里使用
malloc
会导致
mystrncat()
中指定行出现seg故障吗?我的印象是,我可以跨不同的堆栈框架访问堆的元素。有什么资料可以让我更好地理解这个话题吗

多谢各位

编辑:

这是我的更新代码,仍然在这个位置

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

#define initial_malloc 20

char* mystrncat(char *dest, char *source, int n);

int main(void) {
    char *str1 = malloc(initial_malloc);
    char *str2 = malloc(initial_malloc);
    memset(str1, '\0', 20);
    memset(str2, '\0', 20);
    str1 = "hello";
    str2 = "World";

    mystrncat(str1, str2, 3);
    return EXIT_SUCCESS;
}

char *mystrncat(char *dest, char *source, int n) {
    int i, j, k, l;
    j = strlen(dest);
    for (i = 0; i < n && source[i] != '\0'; i++)
        ;
    for (k = j, l = 0; k < (j + i - 1); k++, l++) {
        dest[k] = source[l]; /* <-------runtime error here with malloc */
    }
    dest[k] = '\0';

    return dest;
}
#包括
#包括
#包括
#定义初始值\u malloc 20
char*mystrncat(char*dest,char*source,int n);
内部主(空){
char*str1=malloc(初始值为malloc);
char*str2=malloc(初始值为malloc);
memset(str1,'\0',20);
memset(str2,'\0',20);
str1=“你好”;
str2=“世界”;
mystrncat(str1,str2,3);
返回退出成功;
}
char*mystrncat(char*dest,char*source,int n){
int i,j,k,l;
j=斯特伦(目的地);
对于(i=0;idest[k]=source[l];/*
=
不复制字符串。它只为poiner分配字符串文本的地址(在您的情况下)。字符串文本是只读的,任何写入它们的尝试通常以SEGFULT结束

您需要将文本复制(使用strcpy)到str1中,然后可以对其进行压缩

这里根本不需要第二个字符串(
str2

使用合适的类型(尺寸),尽量保持正确

顺便说一句,你的malloced内存丢失了

稍加修改的版本

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

#define initial_malloc 20

char* mystrncat(char *, const char *, size_t);

int main(void) {
    char *str1 = malloc(initial_malloc);

    if(str1)
    {
        strcpy(str1, "hello");
        mystrncat(str1, "World", 3);
        printf("%s\n", str1);
        free(str1);
    }
    return EXIT_SUCCESS;
}

char *mystrncat(char *dest, const char *src, size_t n) 
{
    char *SavedDest = dest;

    while(*dest++);
    dest--;
    while(n && *src)
    {
        *dest++ = *src++;
        n--;
    }
    *dest = 0;
    return SavedDest;
}
#包括
#包括
#包括
#定义初始值\u malloc 20
char*mystrncat(char*,const char*,size\u t);
内部主(空){
char*str1=malloc(初始值为malloc);
如果(str1)
{
strcpy(str1,“你好”);
mystrncat(str1,“世界”,3);
printf(“%s\n”,str1);
免费(str1);
}
返回退出成功;
}
char*mystrncat(char*dest,const char*src,size\u t n)
{
char*SavedDest=dest;
而(*dest++);
目的地--;
while(n&&*src)
{
*dest++=*src++;
n--;
}
*dest=0;
返回SavedDest;
}

在调用
mystrncat
并使它们指向字符串文本之前,您更改了
str1
str2
。试图修改
str1
指向的内存具有未定义的行为,在您的情况下,这是一个分段错误

由于要初始化分配的内存,请使用
calloc()
,这样可以更有效地执行初始化,并且大小正确。您的代码不使用
initial\u malloc
,因此如果将
initial\u malloc
重新定义为其他值,则可能会失败

您应该输出结果字符串以检查其正确性

还请注意,您的函数
mystrncat
与标准函数
strncat
具有不同的语义。如果这是您的意图,则名称
mystrncat
具有误导性

以下是具有标准语义的修改版本:

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

#define initial_malloc 20

char *mystrncat(char *dest, const char *source, size_t n);

int main(void) {
    char *str1 = malloc(initial_malloc);
    char *str2 = malloc(initial_malloc);
    if (str1 == NULL || str2 == NULL) {
        printf("memory allocation failure\n");
        return EXIT_FAILURE;
    }
    strcpy(str1, "hello");
    strcpy(str2, "World");
    mystrncat(str1, str2, 3);
    printf("%s\n", str1);
    free(str1);
    free(str2);
    return EXIT_SUCCESS;
}

char *mystrncat(char *dest, const char *source, size_t n) {
    size_t i, j;

    for (i = 0, j = strlen(dest); i < n && source[i]; i++, j++) {
        dest[j] = source[i];
    }
    dest[j] = '\0';

    return dest;
}
#包括
#包括
#包括
#定义初始值\u malloc 20
char*mystrncat(char*dest,const char*source,size\u t n);
内部主(空){
char*str1=malloc(初始值为malloc);
char*str2=malloc(初始值为malloc);
如果(str1==NULL | | str2==NULL){
printf(“内存分配失败\n”);
返回退出失败;
}
strcpy(str1,“你好”);
strcpy(str2,“世界”);
mystrncat(str1,str2,3);
printf(“%s\n”,str1);
免费(str1);
免费(str2);
返回退出成功;
}
char*mystrncat(char*dest,const char*source,size\u t n){
尺寸i,j;
对于(i=0,j=strlen(dest);i
您需要在新分配的内存中放入有用的字符串数据。目前它甚至没有以零结尾,更不用说有值“hello”和“world”,因为当您使用
malloc
时,您不会用任何合理的值初始化字符串,包括空终止。您可以使用
calloc(num,size)
并获得零初始化内存。编写的代码(wiithout
malloc()
)也无效,因为
str1
中没有空间添加任何字符。如果它没有崩溃,你只是“幸运”。由于扩展了“str1”,即使没有malloc-UB,它也会停止运行:(相当低效的
mystrncat
function@P_uuj_uu;:与clang的区别不大。假设你的版本没有使用
strlen
,我很震惊,gcc和clang内联
strlen
都不是在
-O3
上。我的意图是保留OP的方法,而不是压缩每一点性能。我们应该展示有效的方法。初学者倾向于在不应该使用索引的地方使用索引。@P_uj_uuu:您是否在各种测试用例上对这两个版本进行了基准测试?从程序集输出来看,哪一个版本更有效并不那么明显。基于索引的访问在现代ALU上大多是免费的。
for(i=0,J=strlen(dest);i
IMO在C语言中,大多数程序员都不会与零相比。
for(i=0,j=strlen(dest);i
IMO更优雅
while(*dest++);
有点不雅,
*dest=0;
会更清晰,因为
*dest='\0';
对性能没有任何影响。@chqrlie这可能是给没有经验的程序员的。
'\0'
在这种情况下:D.这是风格问题。我个人喜欢
而(*dest)继续;
,而且肯定是
*dest='\0';
。还要注意,您的方法并不完全正确:
mystrncat(dest,NULL,0)
将具有未定义的行为。由于您喜欢紧凑性,我建议此修复方法:
而(n--&&*src)*dest++=*src++;
@chqrlie没有从src读取字符-您是对的,顺序应该是