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 时:

  1. 如果 char 是 unsigned,那么你会得到一个无限循环,因为我们永远不会得到 EOF
  2. 如果 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) 的缓冲区 - 如果您不是出于某种原因有严格的内存限制或一个巨大的大文件。