簡體   English   中英

如何對兩個字符串(任意長度)使用 fscanf() 並正確動態分配/取消分配 memory

[英]How to use fscanf() for two strings (of ANY length) and dynamically allocate/de-allocate the memory properly

我需要讀取一個 input.txt 文件並從文件中的每一行打印出兩個單獨的字符串。 我使用了一個 while 循環和一個 fscanf function 來獲取每個字符串並忽略它們之間的空格。 如果輸入文件的一行中的字符串太長,則會出現分段錯誤 但是,當我運行我的可執行文件時,我也會收到一個munmap_chunk(): invalid pointer錯誤。

如果我沒有為 string1 和 string2 分配 memory,fscanf 不能正常工作。 我相信 fscanf 正在更改指向 string1 和 string2 的指針,這導致了 munmap_chunk() 錯誤。 但是,我需要取消分配我給 string1 和 string2 的 memory 所以我沒有 memory 泄漏。

如何掃描此文件中的字符串(任意長度)並正確取消分配 memory?

int main(int argc, char *argv[]) 
{
  char *string1;
  char *string2;
  string1 = (char *)malloc(sizeof(string1)); //these strings need memory allocated for the fscanf to function properly
  string2 = (char *)malloc(sizeof(string2)); 
  FILE* file = fopen(argv[1], "r");
  
  while (fscanf(file, "%s %s", string1, string2) != EOF)
    {
      printf("%s %s\n", string1, string2);
    }
  fclose(file);

  //Deallocating memory
  free(string1);
  free(string2);
  return 0;
}

'fscanf' 不會更改指針,但如果您沒有為輸入分配足夠的空間,它可能會損壞 memory。

而且您沒有正確分配 memory: string1string2是指針,因此您分配的只是指針的大小(取決於您的系統,4 或 8 個字節)。

如果您需要從文件中讀取一行並且事先不知道該行的最大長度,則不能使用fscanf

您需要分配一個起始緩沖區,例如:

string1 = malloc(512 * sizeof(char));

512 是一個任意但相當大的線長度。 然后,您使用fread在循環中一次讀取一個字節,並檢查行尾(通常是 '\n')。

您還必須計算您閱讀了多少,如果該行超過 512 字節,請使用realloc來增加緩沖區的大小,如下所示:

if (bytesRead == (string1Size - 1) && curByte != '\n') {
    string1Size += 512;
    string1 = realloc(string1, string1Size);
}

這里, bytesRead是一個int變量,用於計算到目前為止您成功讀取了多少字節,而string1Size也是用於跟蹤string1緩沖區大小的int變量。

string1 = (char *)malloc(sizeof(string1)); 只為 4 或 8 個字符分配 memory 因為 string1 是一個char * ,這就是指針的大小。

要為 memory 分配 100 個字符,您需要執行char *string1 = malloc(sizeof(char) * 100)

如何掃描此文件中的字符串(任意長度)並正確取消分配 memory?

您不能使用fscanf ,因為它將讀取輸入與解析輸入混合在一起。 在解析之前,您不知道將要讀取什么。

相反,將該行讀入一個可以檢查的大緩沖區。 一旦你知道碎片有多大,你就可以分配適量的 memory 並復制到它。

因為我們正在重用行緩沖區,並在完成后將其丟棄,所以我們可以將其設置為我們認為需要的大小。 1024 或 4096 通常是不錯的選擇。 我喜歡BUFSIZ

char line[BUFSIZ];
while( fgets(line, sizeof(line), file) ) {
  // now parse line
}

解析可以通過多種方式完成。 一個簡單的就是strtok (STRing TOKenize)。 這將線標記到位。 使用strdup將它們復制到適量的 memory 中。

char line[BUFSIZ];
while( fgets(line, sizeof(line), file) ) {
  char words[2];
  int i = 0;

  for(
    char *word = strtok(line, " ");
    word;
    word = strtok(NULL, " ")
  ) {
    words[i] = strdup(word);
    i++;
  }

  printf("%s %s", words[0], words[1]);
  free(words[0]);
  free(words[1]);
}

linewords在堆棧上分配,它們將被自動釋放。 但是strdup分配的memory在堆上,需要釋放。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM