c中的字符串文字
String literals in c
我在使用 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] = '[=10=]';
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(..) 时崩溃,删除它们后程序运行正常,但我觉得这是内存泄漏。
将 line = realloc(line, (sizeof(char) * index));
更改为
line = realloc(line, (sizeof(char) * (index+1)));
您正在尝试将 line
重新分配为 index
大小,而下一条语句您正在尝试将 '\0' 字符存储在 line[index]
中,这是未定义的行为。
为数组分配的内存不足。您刚刚为字符数组分配了内存,但没有为终止 [=13=]
字符分配内存。这会导致未定义的行为。
请更改以下行:
line = realloc(line, (sizeof(char) * index));
到
line = realloc(line, (sizeof(char) * (index+1)));
此外,将 ch
的数据类型从 char
更改为 int,因为 fgetc()
的 return 类型是 int
(不是 char
).建议将 returned 值赋值给整型变量。
当您将值读入 char
而不是 int
时:
- 如果 char 是
unsigned
,那么你会得到一个无限循环,因为我们永远不会得到 EOF
。
- 如果 char 是
signed
,则 0xFF
(即 ÿ
被接受为 EOF)被认为是 EOF
产生错误结果。
Also, check whether the functions worked as intended or not:
- 检查文件打开是否成功。
文件* fp = fopen(file_path, "r");
如果(fp!= NULL){
//做东西
}
检查内存是否分配
char* tmpLine = realloc(line, (sizeof(char) * (index+1)));
if (tmpLine != NULL)
{
line = tmp;
line[index] = '[=12=]';
}
else
{
//Handle insufficient memory
}
在 C 中,检查具有 return 值的函数中的 return 值很重要。在您的情况下,您使用 realloc 但不必费心检查 return 值。
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] = '[=11=]';
}
一般来说,边做边分配有点无效,如果先检查文件的大小会更有效(例如,看到 fseek 到最后,然后执行 ftell 然后 fseek 开始)和然后在读取之前分配一个具有相同大小 (+1) 的缓冲区 - 如果您不是出于某种原因有严格的内存限制或一个巨大的大文件。
我在使用 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] = '[=10=]';
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(..) 时崩溃,删除它们后程序运行正常,但我觉得这是内存泄漏。
将 line = realloc(line, (sizeof(char) * index));
更改为
line = realloc(line, (sizeof(char) * (index+1)));
您正在尝试将 line
重新分配为 index
大小,而下一条语句您正在尝试将 '\0' 字符存储在 line[index]
中,这是未定义的行为。
为数组分配的内存不足。您刚刚为字符数组分配了内存,但没有为终止 [=13=]
字符分配内存。这会导致未定义的行为。
请更改以下行:
line = realloc(line, (sizeof(char) * index));
到
line = realloc(line, (sizeof(char) * (index+1)));
此外,将 ch
的数据类型从 char
更改为 int,因为 fgetc()
的 return 类型是 int
(不是 char
).建议将 returned 值赋值给整型变量。
当您将值读入 char
而不是 int
时:
- 如果 char 是
unsigned
,那么你会得到一个无限循环,因为我们永远不会得到EOF
。 - 如果 char 是
signed
,则0xFF
(即ÿ
被接受为 EOF)被认为是EOF
产生错误结果。
Also, check whether the functions worked as intended or not:
- 检查文件打开是否成功。 文件* fp = fopen(file_path, "r"); 如果(fp!= NULL){ //做东西 }
检查内存是否分配
char* tmpLine = realloc(line, (sizeof(char) * (index+1))); if (tmpLine != NULL) { line = tmp; line[index] = '[=12=]'; } else { //Handle insufficient memory }
在 C 中,检查具有 return 值的函数中的 return 值很重要。在您的情况下,您使用 realloc 但不必费心检查 return 值。
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] = '[=11=]';
}
一般来说,边做边分配有点无效,如果先检查文件的大小会更有效(例如,看到 fseek 到最后,然后执行 ftell 然后 fseek 开始)和然后在读取之前分配一个具有相同大小 (+1) 的缓冲区 - 如果您不是出于某种原因有严格的内存限制或一个巨大的大文件。