我想创建一个函数,从给定的文本文件中读取您选择的行。继续作为参数的函数(int fd
打开和int line_number
)它必须使用语言C和Unix系统调用(read
和/或open
)来做到这一点。它还应该读取任何空格,并且它不能有真正的限制(即行必须能够具有您选择的长度)。我做的函数是这样的:
char* read_line(int file, int numero_riga){
char myb[1];
if (numero_riga < 1) {
return NULL;
}
char* myb2 = malloc(sizeof(char)*100);
memset(myb2, 0, sizeof(char));
ssize_t n;
int i = 1;
while (i < numero_riga) {
if((n = read(file, myb, 1)) == -1){
perror("read fail");
exit(EXIT_FAILURE);
}
if (strncmp(myb, "n", 1) == 0) {
i++;
}else if (n == 0){
return NULL;
}
}
numero_riga++;
int j = 0;
while (i < numero_riga) {
ssize_t n = read(file, myb, 1);
if (strncmp(myb, "n", 1) == 0) {
i++;
}else if (n == 0){
return myb2;
}else{
myb2[j] = myb[0];
j++;
}
}
return myb2;
}
直到最近,我还认为这会起作用,但它确实存在一些问题。使用消息队列,read_line
读取的字符串将作为空字符串 ("\0") 接收。我知道消息队列不是问题,因为尝试传递普通字符串并没有产生问题。如果可能的话,我想要一个修复程序,并解释为什么我应该以某种方式纠正它。这是因为如果我不理解我的错误,我就有可能在未来重蹈覆辙。
编辑 1.根据答案,我决定添加一些问题。如何结束 myb2?有人可以根据我的代码给我一个示例吗?我如何提前知道构成一行 txt 要读取的字符数?
编辑 2.我不知道该行有多少字符,所以我不知道要分配多少字符;这就是我使用*100
.
部分分析
您在以下位置出现内存泄漏:
char* myb2 = (char*) malloc((sizeof(char*))*100);
memset(myb2, 0, sizeof(char));
if (numero_riga < 1) {
return NULL;
}
在分配内存之前检查numero_riga
。
以下循环充其量也是可疑的:
int i = 1;
while (i < numero_riga) {
ssize_t n = read(file, myb, 1);
if (strncmp(myb, "n", 1) == 0) {
i++;
}else if (n == 0){
return NULL;
}
}
您不会检查read()
是否真的足够快地返回了任何内容,并且当您进行检查时,您会泄漏内存(再次)并忽略事先读取的任何内容,并且不会检测到错误(n < 0
)。 当您检测到换行符时,您只需将 1 添加到 i
中即可。 任何时候都不会将读取的字符保存在缓冲区中(例如 myb2
)。 总而言之,这似乎已经彻底崩溃了...除非...除非您尝试从头开始读取文件中的第 N 行,而不是文件中的下一行,这更常见。
您需要做的是:
- 扫描N-1线,注意EOF
- 而另一个字节可用
- 如果是换行符,则终止字符串并返回
- 否则,请将其添加到缓冲区,如果没有空间,则分配空间。
实现
我想我可能会使用这样的函数get_ch()
:
static inline int get_ch(int fd)
{
char c;
if (read(fd, &c, 1) == 1)
return (unsigned char)c;
return EOF;
}
然后在主char *read_nth_line(int fd, int line_no)
函数中,您可以执行以下操作:
char *read_nth_line(int fd, int line_no)
{
if (line_no <= 0)
return NULL;
/* Skip preceding lines */
for (int i = 1; i < line_no; i++)
{
int c;
while ((c = get_ch(fd)) != 'n')
{
if (c == EOF)
return NULL;
}
}
/* Capture next line */
size_t max_len = 8;
size_t act_len = 0;
char *buffer = malloc(8);
int c;
while ((c = get_ch(fd)) != EOF && c != 'n')
{
if (act_len + 2 >= max_len)
{
size_t new_len = max_len * 2;
char *new_buf = realloc(buffer, new_len);
if (new_buf == 0)
{
free(buffer);
return NULL;
}
buffer = new_buf;
max_len = new_len;
}
buffer[act_len++] = c;
}
if (c == 'n')
buffer[act_len++] = c;
buffer[act_len] = ' ';
return buffer;
}
添加的测试代码:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
extern char *read_nth_line(int fd, int line_no);
…code from main answer…
int main(void)
{
char *line;
while ((line = read_nth_line(0, 3)) != NULL)
{
printf("[[%s]]n", line);
free(line);
}
return 0;
}
这将从标准输入中读取每三行。 它似乎工作正常。 最好对边界条件(短线等)进行更详尽的检查,以确保它不会滥用内存。 (测试长度为 1 的行 — 仅限换行符 — 最多 18 个字符,valgrind
表明它没问题。 随机较长的测试似乎也是正确的。