为什么使用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;i dest[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)
并获得零初始化内存。编写的代码(wiithoutmalloc()
)也无效,因为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读取字符-您是对的,顺序应该是