当我在eclipse上构建下面的代码时,命令行上的所有内容都按预期工作,输出文件上的所有内容都按预期工作。

#include <stdio.h>
#include <stdlib.h> // for exit()
#include <string.h>
int main(int argc, char *argv[])
{
FILE *in, *out; // declare two FILE pointers
int ch;
// check for command-line arguments
if (argc < 2)
{
    fprintf(stderr, "Usage: %s filename\n", argv[0]);
    exit(EXIT_FAILURE);
}
// set up input
if ((in = fopen(argv[1], "r")) == NULL)
{
    fprintf(stderr, "I couldn't open the file \"%s\"\n",
        argv[1]);
    exit(EXIT_FAILURE);
}
// set up output
char *ptd;
ptd = (char*)malloc(150 * sizeof(char));
char x;
int i = 0;
while ((x = getchar()) != '\n'){
    ptd[i] = x;
    i++;
}
ptd[i + 1] = '\0';
strcat(ptd, ".txt"); // append .txt
if ((out = fopen(ptd, "w")) == NULL)
{ // open file for writing
    fprintf(stderr, "Can't create output file.\n");
    exit(3);
}
// copy data
while ((ch = getc(in)) != EOF)
        putc(ch, out); // print every 3rd char
// clean up
if (fclose(in) != 0 || fclose(out) != 0)
    fprintf(stderr, "Error in closing files\n");
free(ptd);
return 0;
}

但是当我用visual studio构建它时,我会在我的文件名之后得到这个东西“Í”,直到它到达.txt并使用所有分配的内存作为文件名。为什么会这样?

最佳答案

int i = 0;
while ((x = getchar()) != '\n'){
    ptd[i] = x;
    i++;               <=== increment, hence 'i' points to the char *after* the last one
}
ptd[i + 1] = '\0';     <== now you move *one char more* from the last one
strcat(ptd, ".txt"); // append .txt

其工作原理如下:
输入字符串(来自getchar)="abc\n"
mallocptd[]=<junk>之后
读取stdinptd[]="abc"<junk>
while循环后i==3并指向<junk>其余部分的第一个字节;
现在ptd[i+1]设置为ptd[4]
ptd的样子是这样的:0
因为ptd[]="abc"<junk char><zero>不会将内存初始化为零(malloc会),所以在GCC中只是发生了在visual studio中为零而不是零的情况。
为什么?
您仍然可以在eclipse中重现这一点。
calloc行之前,添加一个循环以从堆中分配并填充垃圾,以使ptd = (char*)malloc(150 * sizeof(char));重用该垃圾。
char *p[20];
int n,j;
for(n=0;n<20;++n)
{
    p[n]=(char*)malloc(150 * sizeof(char));
    for(j=0;j<150;++j)
    {
        p[n][j]=(char)n*11+j+3;
    }
}

for(n=0;n<20;++n)
{
    free(p[n]);
}

这意味着(可能)用GCC编译的程序以干净堆开始,而MSVC以充满垃圾的堆开始。
MSVC可以在堆中填充垃圾时这样做,这有助于像您这样检测人为错误。
查看此页:https://msdn.microsoft.com/en-us/library/974tc9t1.aspx部分“使用调试堆查找缓冲区溢出”:
调试堆还用已知值填充新的内存块。
目前,实际使用的字节值如下:
新对象(0xCD)
分配新对象时,将用0xCD填充它们。
那么,如果你看这里:http://www.idautomation.com/product-support/ascii-chart-char-set.html
你会看到:
Í205 0xcd 0315Í附言(“)hungarumlaut
就是你在文件名中看到的那个字符。

08-04 18:32