我在C
和字符数组方面遇到了一些麻烦。我尝试搜索SO,但我没有看到任何可以帮助我的东西,或者我没有找到正确的东西。
我有这个功能:
char* readFile(char* file_path)
{
FILE* fp = fopen(file_path, "r");
size_t buffer = 4096;
char ch;
int index = 0;
char* line = (char*)malloc(sizeof(char) * buffer);
while( (ch = (char)fgetc(fp)) != EOF )
{
line[index] = ch;
++index;
if(index == buffer -1)
{
buffer = buffer * 2;
line = realloc(line, buffer);
}
}
line = realloc(line, (sizeof(char) * index));
line[index] = '\0';
fclose(fp);
return line;
}
现在,当我在我的代码中使用此函数并尝试释放引用时,它会导致崩溃,所以我认为我在某处泄漏了内存。
char* data;
data = readFile("....");
free(data) <-- this line causes a crash!
我知道如果我在函数内没有malloc
,那么内存就会超出范围,这样就不行了,但是按原样使用当前函数,我就崩溃了。我做错了什么?
修改 执行此读取文件后
在上面的readFile函数之后我进入了这个函数
GLuint getShaderProgram(const char* vshad, const char* fshad)
{
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vshad, NULL);
glCompileShader(vertexShader);
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
printf("ERROR VERTEX COMPILATION_FAILED %s\n",infoLog);
SDL_Quit();
}
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fshad, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
printf("ERROR FRAGMENT COMPILATION_FAILED %s\n",infoLog);
SDL_Quit();
}
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if(!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
printf("ERROR SHADER PROGRAM COMPILATION_FAILED %s\n",infoLog);
SDL_Quit();
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return shaderProgram;
}
所以完整的代码路径就像这样
char* vv = readFile("vshad.vs");
char* ff = readFile("fshad.fs");
sp = getShaderProgram(vv, ff);
free(vv);
free(ff);
我在free(..)崩溃,删除那些并且程序运行正常,但我觉得它是内存泄漏。
答案 0 :(得分:3)
为阵列分配的内存不足。您只需为字符数组分配内存,但不为终止\0
字符分配内存。这会导致未定义的行为。
请更改以下行:
line = realloc(line, (sizeof(char) * index));
到
line = realloc(line, (sizeof(char) * (index+1)));
此外,将ch
的数据类型更改为char
的int,因为fgetc()
的返回类型为int
(不是char
)。建议将返回的值赋给整数类型变量。
当您将值读入char
而不是int
时:
unsigned
,那么您将获得无限循环,因为我们永远不会EOF
。signed
,那么0xFF
(即ÿ
被接受为EOF)会被视为EOF
,会产生错误的结果。另外,检查功能是否按预期工作:
检查内存是否已分配
char* tmpLine = realloc(line, (sizeof(char) * (index+1)));
if (tmpLine != NULL)
{
line = tmp;
line[index] = '\0';
}
else
{
//Handle insufficient memory
}
答案 1 :(得分:2)
在C中,检查具有返回值的函数的返回值非常重要。在您的情况下,您使用realloc,但不要检查返回值。
char* tmp = realloc(line, newbuffersize);
if (tmp != NULL)
{
line = tmp;
}
else
{
abort();
}
您应该检查文件是否已正确打开,如果文件失败并且您在调用中开始使用空指针,则会产生有趣的行为。
离开while循环后,使用新的realloc缩小缓冲区的大小。这没关系,但你需要为结尾添加空间\ 0:
char* tmp = realloc(line, index + 1);
if (tmp != NULL)
{
line = tmp;
line[index] = '\0';
}
一般来说,分配它有点无效,如果首先检查文件的大小(例如,请查看fseek到最后然后执行ftell然后fseek开始)会更有效,然后分配读取之前具有相同大小(+1)的缓冲区 - 如果由于某种原因您没有严格的内存限制或大量文件。
答案 2 :(得分:1)
将line = realloc(line, (sizeof(char) * index));
更改为
line = realloc(line, (sizeof(char) * (index+1)));
您正尝试将line
重新分配到index
大小,然后尝试在line[index]
中存储'\ 0'字符,这是未定义的行为。