-9 c malloc portability string.h c17
我正在尝试以可移植的方式使这种动态重新分配工作。
我的程序接受用户的一行文本并将其附加到缓冲区。如果缓冲区中的文本长度为20个或更多,它将删除前20个字符,并将其后的所有字符移到缓冲区的开头。
我有这段代码可以在Linux上正常工作,但是当我在Windows上运行它时会发出垃圾。有谁知道为什么/如何仅使用malloc使其具有可移植性。IE浏览器不使用string.h(strcpy)的str ...除了伦。
仅限于c17-无折断的钉子(不可移植)。这是我的代码。编译无误gcc 7.3,mingw 7.3。我用更安全的功能替换了gets和puts函数,但在Windows上仍然出现垃圾。我认为这是一个格式问题...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
void wbuff (message)
char *message;
{
FILE *f = fopen("file.txt", "w");
fprintf(f, "%s", message);
fclose(f);
}
char *rean (message)
char *message;
{
/* performs (write) on buffer, trims lefover, then restores */
char buf[80] = "";
puts("enter a line");
gets(buf);
int bln = strlen( buf );
int mln = strlen( message );
int nln = bln + mln;
printf("new length %d\n", nln);
message = realloc(message, nln);
memmove(message + mln, buf, bln);
/* MISTAKE IS HERE?! */
if( nln >= 20 ) {
int exl = nln -20; // leftover length
char *lo = realloc(NULL, exl); // leftover placeholder
memmove(lo, message+20, exl); // copy leftover
wbuff(message); // write clear buff
message = realloc(NULL, nln);
message = realloc(NULL, exl); // resize buffer
memmove(message, lo, exl); // restore leftover
}
return message;
}
void main (void)
{
char *message = "";
message = realloc(NULL, 0);
while ( 1 == 1 ) {
message = rean( message );
puts(message);
}
return;
}
Run Code Online (Sandbox Code Playgroud)
在C语言中,字符串是一个以空字节结尾的字符序列。您这里有许多偏离一处的错误,大多数与不考虑该事实以及内存泄漏有关。
首次设置message时main:
char *message = "";
message = realloc(NULL, 0);
Run Code Online (Sandbox Code Playgroud)
message任一个为NULL均指向0字节的内存。通话时rean,第一次通话:
int mln = strlen( message );
Run Code Online (Sandbox Code Playgroud)
您正在尝试取消引用NULL指针以读取分配的内存末尾。您想要分配至少1个字节来开始并将该字节设置为0,以便您有一个空字符串:
char *message = realloc(NULL, 1);
message[0] = '\0';
Run Code Online (Sandbox Code Playgroud)
然后,当您将缓冲区复制到消息中时:
message = realloc(message, nln);
memmove(message + mln, buf, bln);
Run Code Online (Sandbox Code Playgroud)
您没有为终止的空字节分配足够的空间,也没有复制它,因此您实际上没有字符串。然后,当您尝试打印它时,将读取puts或printf读取超出分配的内存末尾的内容。您需要分配1个额外的字节并复制1个额外的字节:
message = realloc(message, nln + 1); // allocate 1 extra byte for the null terminator
memmove(message + mln, buf, bln + 1); // copy 1 extra byte
Run Code Online (Sandbox Code Playgroud)
当您重新复制超过20个字符的内容时,也会遇到类似的问题:
int exl = nln -20; // leftover length
char *lo = realloc(NULL, exl); // leftover placeholder
memmove(lo, message+20, exl); // copy leftover
wbuff(message); // write clear buff
message = realloc(NULL, nln);
message = realloc(NULL, exl); // resize buffer
memmove(message, lo, exl); // restore leftover
Run Code Online (Sandbox Code Playgroud)
lo也不会复制它。 message第一个保留的内存reallocmessageNULL和以前一样,为每个分配分配1个额外的字节,并移动1个额外的字节以说明空终止符。另外,lo在代码块的末尾释放,删除多余的reallocfor message,并传递messageto 的先前值,realloc以免泄漏内存:
int exl = nln -20;
char *lo = realloc(NULL, exl + 1); // allocate 1 extra byte
memmove(lo, message+20, exl + 1); // copy 1 extra byte
wbuff(message);
// remove extra realloc
message = realloc(message, exl + 1); // pass in old message, allocate 1 extra
memmove(message, lo, exl + 1); // copy 1 extra byte
free(lo); // free leftover
Run Code Online (Sandbox Code Playgroud)
这些超出分配的内存末尾的读取和写入问题均调用未定义的行为,这解释了为什么您在不同的操作系统上看到不同的结果。
就符合标准的代码而言,请使用fgetsintead gets:
fgets(line, sizeof(line), stdin);
Run Code Online (Sandbox Code Playgroud)
line如果有足够的空间,此函数将在其中包含换行符,因此请务必删除它。
还更改main为return int,并删除,#include <malloc.h>因为malloc函数族定义为驻留在中stdlib.h。
如果您使用了strcpy而strcat不是memmove,那么您将不必考虑复制空终止字节,因为这些函数会为您完成复制。但是,在分配内存时,您仍然需要考虑到这一点。还有之间没有冲突strcpy,malloc和realloc,因为他们是标准和工作的各个部分一起正常。一起使用它们没有问题。如果它们不能为您正常工作,则说明您没有正确使用它们。
应用我的更新后,可以替换为:
memmove(message + mln, buf, bln + 1);
Run Code Online (Sandbox Code Playgroud)
有了这个:
strcat(message, buf);
Run Code Online (Sandbox Code Playgroud)
并替换为:
memmove(lo, message+20, exl + 1); // copy leftover
...
memmove(message, lo, exl + 1); // restore leftover
Run Code Online (Sandbox Code Playgroud)
有了这个:
strcpy(lo, message+20);
...
strcpy(message, lo);
Run Code Online (Sandbox Code Playgroud)
而且它将仍然可以正常工作并保持一致。