[英]Dynamic array of strings in C is not working properly
我在 C 中創建動態字符串數組時遇到了麻煩。 我沒有得到預期的結果,我想知道為什么?
readLine() function 將分別讀取每一行,並在必要時進行一些更改:
char *readLine(FILE *f, size_t *len)
{
char *line = NULL;
ssize_t nread;
if (f == NULL)
{
return NULL;
}
if ((nread = getline(&line, len, f)) != -1)
{
if (line[nread - 1] == '\n')
{
line[strlen(line)-1] = '\0';
*len = strlen(line);
}
return line;
}
else
{
return NULL;
}
}
readFile() function 將在使用 readLine 讀取所有行之后返回一個字符串數組,然后將它們存儲到字符串數組中:
char **readFile(const char *filename, size_t *fileLen)
{
char *result;
int idx = 0;
char **array = calloc(1, sizeof(char*) );
if (filename == NULL || fileLen == NULL)
{
return NULL;
}
FILE *f = fopen(filename, "r");
if (f == NULL)
{
return NULL;
}
while (1)
{
result = readLine(f, fileLen);
if (result == NULL)
break;
else
{
*(array + idx) = malloc(LENGTH * sizeof(char *));
strncpy(array[idx], result, strlen(result) + 1);
idx++;
array = realloc(array, (idx + 1) * sizeof(char *));
}
}
return array;
}
在 main 中,我創建了一個臨時文件來測試我的功能,但它不能正常工作:
int main()
{
char filename[] = "/tmp/prefXXXXXX";
int fd;
size_t len = 0;
FILE *f;
if (-1 == (fd = mkstemp(filename)))
perror("internal error: mkstemp");
if (NULL == (f = fdopen(fd, "w")))
perror("internal error: fdopen");
for (int i = 0; i < 10000; i++)
fprintf(f, "%d\n", i);
fclose(f);
char **number = readFile(filename, &len);
for (int i = 0; i < sizeof(number) / sizeof(number[0]); i++)
printf("number[%i] = %s\n", i, number[i]);
return 0;
}
當我執行程序時,我得到以下 output:
number[0] = 0
我在這里做錯了什么?
該代碼中有很多問題,很難找到從哪里開始......
我們來看看每個 function。
char *readLine(FILE *f, size_t *len)
{
char *line = NULL;
ssize_t nread;
if (f == NULL)
{
return NULL;
}
if ((nread = getline(&line, len, f)) != -1)
{
if (line[nread - 1] == '\n')
{
line[strlen(line)-1] = '\0';
*len = strlen(line);
}
return line;
}
else
{
return NULL;
}
}
這里沒有太大的錯誤。 但是geline的手冊頁告訴我們:
如果 *lineptr 在調用之前設置為
NULL
,那么getline()
將分配一個緩沖區來存儲該行。 即使getline()
失敗,該緩沖區也應該由用戶程序free
。
如果nread==-1
則不free
緩沖區,而只return NULL;
可能導致 memory 泄漏。
您還應該檢查len==NUL
是否已經使用f
進行了檢查。
然后看下function:
char **readFile(const char *filename, size_t *fileLen)
{
char *result;
int idx = 0;
char **array = calloc(1, sizeof(char*) );
if (filename == NULL || fileLen == NULL)
{
return NULL;
}
FILE *f = fopen(filename, "r");
if (f == NULL)
{
return NULL;
}
while (1)
{
result = readLine(f, fileLen);
if (result == NULL)
break;
else
{
*(array + idx) = malloc(LENGTH * sizeof(char *));
strncpy(array[idx], result, strlen(result) + 1);
idx++;
array = realloc(array, (idx + 1) * sizeof(char *));
}
}
return array;
}
在此 function 中,如果您遇到return NULL;
您將無法free(array)
; 出口。
readLine
將strlen(result)
放入filelen
。 為什么不用它來分配memory? 相反,您采用一些未知的固定長度LENGTH
可能足以或可能不足以容納字符串。 相反,您應該使用fileLen+1
或strlen(result)+1
,就像使用strncpy
一樣。
您還使用了錯誤類型的大小。 您分配一個指向char
的指針,而不是char*
。 由於char
的大小定義為 1,您可以將大小部分放在這里。
然后, strncpy
的長度參數應該保存目標的長度,而不是源的長度。 否則使用strncpy
完全沒用。 正如您已經(應該)使用字符串長度來分配 memory 一樣,只需使用strncpy
。
然后,只是將fileLen
傳遞給下一個 function 是沒有意義的。 在readLine
中,它意味着在readFile
中沒有任何意義的行的長度。 相反,它應該意味着行數。 正如我們剛剛談到的主題......您應該將一些值傳遞給調用者。
最后,您不應該將realloc
的返回值直接分配給您傳遞給它的變量。 如果出現錯誤,將返回NULL
並且您不能再訪問或釋放舊指針。
該塊應如下所示:
{
array[idx] = malloc(fileLen+1);
strcpy(array[idx], result);
idx++;
void *temp = realloc(array, (idx + 1) * sizeof(char *));
if (temp != NULL)
array = temp;
// TODO: else <error handling>
}
}
*fileLen = idx;
return array;
}
這仍然存在一個缺陷,即您為另一個不使用的指針分配了 memory。 您可以將其更改為進一步優化。
最后是main
的function:
int main()
{
char filename[] = "/tmp/prefXXXXXX";
int fd;
size_t len = 0;
FILE *f;
if (-1 == (fd = mkstemp(filename)))
perror("internal error: mkstemp");
if (NULL == (f = fdopen(fd, "w")))
perror("internal error: fdopen");
for (int i = 0; i < 10000; i++)
fprintf(f, "%d\n", i);
fclose(f);
char **number = readFile(filename, &len);
for (int i = 0; i < sizeof(number) / sizeof(number[0]); i++)
printf("number[%i] = %s\n", i, number[i]);
return 0;
}
char **number = readFile(filename, &len);
你得到一個包含文件所有行的數組。 number
是一個非常糟糕的名字。
如果出現錯誤,您可以從readFile
return NULL
。 你應該在打電話后檢查一下。
然后你忘了 arrays 不是指針,指針也不是 arrays。 它們在許多地方的行為相似,但同時又非常不同。
i < sizeof(number) / sizeof(number[0])
這里的number
是一個指針,它的大小是一個指針的大小。 number[0]
也是一個指針。 不同的類型,但大小相同。 您想要的是從readFile
獲得的行數。 使用該變量。
這部分應該如下所示:
char **all_lines = readFile(filename, &len);
if (all_lines != NULL)
{
for (int i = 0; i < len; i++)
printf("all_lines[%i] = %s\n", i, all_lines[i]);
而且你不應該忘記你已經分配了很多 memory 你也應該釋放它們。 (當你終止你的程序時,這可能不是絕對必要的,但你應該記住在你身后清理)
if (all_lines != NULL)
{
for (int i = 0; i < len; i++)
printf("all_lines[%i] = %s\n", i, all_lines[i]);
for (int i = 0; i < len; i++)
free(all_lines[i];
free(all_lines);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.