gpt4 book ai didi

c - C-无法将文本文件中的字符串列表读取并处理到数组中

转载 作者:行者123 更新时间:2023-11-30 20:54:16 24 4
gpt4 key购买 nike

此代码逐行读取文本文件。但是我需要将这些行放在一个数组中,但是我却做不到。现在我不知何故得到了一系列数字。那么如何将文件读入列表。我尝试使用二维列表,但是效果不佳。

我是C语言的新手。我主要使用Python,但现在我想检查C对于某个任务而言是否更快。

#include <stdio.h>
#include <time.h>
#include <string.h>


void loadlist(char *ptext) {

char filename[] = "Z://list.txt";
char myline[200];
FILE * pfile;
pfile = fopen (filename, "r" );

char larray[100000];
int i = 0;
while (!feof(pfile)) {
fgets(myline,200,pfile);
larray[i]= myline;
//strcpy(larray[i],myline);
i++;
//printf(myline);

}


fclose(pfile);
printf("%s \n %d \n %d \n ","while doneqa",i,strlen(larray));
printf("First larray element is: %d \n",larray[0]);

/* for loop execution */
//for( i = 10; i < 20; i = i + 1 ){
// printf(larray[i]);
//}


}


int main ()
{
time_t stime, etime;
printf("Starting of the program...\n");
time(&stime);

char *ptext = "String";
loadlist(ptext);
time(&etime);

printf("time to load: %f \n", difftime(etime, stime));

return(0);
}


此代码逐行读取文本文件。但是我需要将这些行放在一个数组中,但是我却做不到。现在我不知何故得到了一系列数字。

最佳答案

有许多方法可以正确执行此操作。首先,首先要弄清您实际需要/想要存储的内容,然后弄清楚该信息来自何处,最后决定如何为信息提供存储。在您的情况下,显然希望loadlist加载行列表(最多10000),以便可以通过静态声明的指针数组进行访问。 (您还可以动态分配指针,但是如果您知道它们不需要多于X,则静态声明它们就可以了(直到导致StackOverflow的地步...)

读取loadlist中的行后,则需要提供足够的存储空间来容纳该行(加上nul终止符)。否则,您只是在计算行数。在您的情况下,由于您声明了一个指针数组,因此您不能简单地复制读取的行,因为数组中的每个指针尚未指向任何已分配的内存块。 (您不能使用fgets (buffer, size, FILE*)分配读取行的缓冲区的地址,因为(1)它是loadlist函数的本地地址,并且在函数返回时销毁函数堆栈帧时,该地址将消失;以及(2)显然,每次调用fgets都会覆盖它。

那么该怎么办?这也非常简单,只需使用@iharob所说的使用每行的strlen为每行分配存储,就像@iharob所说的(+1为nul-byte),然后malloc分配一个大小为该大小的内存块。然后,您可以简单地将读取缓冲区复制到创建的内存块中,并将指针分配给您的list(例如,代码中的larray[x])。现在,gnu扩展提供了一个strdup函数,该函数既可以分配也可以复制,但是要了解它不是C99标准的一部分,因此您会遇到可移植性问题。 (还请注意,如果您担心内存重叠区域,可以使用memcpy,但是由于您正在从文件中读取行,因此我们暂时将其忽略)

分配内存的规则是什么?好吧,您用malloccallocrealloc进行分配,然后在继续操作之前验证对这些函数的调用是否成功,或者您通过写入实际上不是实际的内存区域而进入了未定义行为的领域分配给您使用。看起来像什么?如果您有指针数组p,并且想要将读取缓冲区buf中长度为len的字符串存储在索引idx处,则可以简单地执行以下操作:

    if ((p[idx] = malloc (len + 1)))    /* allocate storage */
strcpy (p[idx], buf); /* copy buf to storage */
else
return NULL; /* handle error condition */


现在,您可以按照以下说明在测试之前自由分配,但是将分配作为测试的一部分很方便。长格式为:

    p[idx] = malloc (len + 1);          /* allocate storage */

if (p[idx] == NULL) /* validate/handle error condition */
return NULL;

strcpy (p[idx], buf); /* copy buf to storage */


您要如何操作取决于您。

现在,您还需要防止指针数组末尾之外的读取。 (自定义数组以来,您只有一个固定的数字)。您可以非常轻松地使该检查成为读取循环的一部分。如果您为拥有的指针数声明了一个常量(例如 PTRMAX),则可以执行以下操作:

int idx = 0;            /* index */

while (fgets (buf, LNMAX, fp) && idx < PTRMAX) {
...
idx++;
}


通过对照可用指针的数量检查索引,可以确保您不会尝试将地址分配给比您拥有的指针更多的指针。

还有一个未解决的问题,该问题将处理读取缓冲区末尾包含的 '\n'。回想一下, fgets最多读取并包括 '\n'。您不希望换行符悬挂在存储的字符串的末尾,因此您只需用一个以nul结尾的字符覆盖 '\n'(例如,简单地用十进制 0或等效的nul字符 '\0' –您可以选择) )。您可以在 strlen调用后进行一次简单的测试,例如

while (fgets (buf, LNMAX, fp) && idx < PTRMAX) {

size_t len = strlen (buf); /* get length */

if (buf[len-1] == '\n') /* check for trailing '\n' */
buf[--len] = 0; /* overwrite '\n' with nul-byte */
/* else { handle read of line longer than 200 chars }
*/
...


(请注意:这还会引起读取行的长度大于为读取缓冲区分配的 200字符的问题。您可以通过检查 fgets是否包含 '\n'来检查是否已读取完整行。最后,如果没有,您将知道您对下一个 fgets的调用将再次从同一行读取,除非遇到 EOF,在这种情况下,您只需要 realloc您的存储并附加任何其他内容同一行中的字符-留待以后讨论)

如果将所有部分放在一起,并为 loadlist选择可以指示成功/失败的返回类型,则可以执行以下操作:

/** read up to PTRMAX lines from 'fp', allocate/save in 'p'.
* storage is allocated for each line read and pointer
* to allocated block is stored at 'p[x]'. (you should
* add handling of lines greater than LNMAX chars)
*/
char **loadlist (char **p, FILE *fp)
{
int idx = 0; /* index */
char buf[LNMAX] = ""; /* read buf */

while (fgets (buf, LNMAX, fp) && idx < PTRMAX) {

size_t len = strlen (buf); /* get length */

if (buf[len-1] == '\n') /* check for trailing '\n' */
buf[--len] = 0; /* overwrite '\n' with nul-byte */
/* else { handle read of line longer than 200 chars }
*/

if ((p[idx] = malloc (len + 1))) /* allocate storage */
strcpy (p[idx], buf); /* copy buf to storage */
else
return NULL; /* indicate error condition in return */

idx++;
}

return p; /* return pointer to list */
}


注意:您可以轻松地将返回类型更改为 int并返回读取的行数,或将指针传递给 int(或者更好的是 size_t)作为参数来使存储的行数可用返回调用函数。

但是,在这种情况下,我们已经使用了指向 NULL的指针数组中所有指针的初始化,因此回到调用函数中,我们只需要遍历指针数组直到遇到第一个 NULL即可遍历我们的行列表。放一个简短的示例程序,从程序的第一个参数给出的文件名中读取/存储所有行(最多 PTRMAX行)(如果未提供文件名,则从 stdin读取/存储所有行),您可以执行以下操作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

enum { LNMAX = 200, PTRMAX = 10000 };

char **loadlist (char **p, FILE *fp);

int main (int argc, char **argv) {

time_t stime, etime;
char *list[PTRMAX] = { NULL }; /* array of ptrs initialized NULL */
size_t n = 0;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}

printf ("Starting of the program...\n");

time (&stime);
if (loadlist (list, fp)) { /* read lines from fp into list */
time (&etime);
printf("time to load: %f\n\n", difftime (etime, stime));
}
else {
fprintf (stderr, "error: loadlist failed.\n");
return 1;
}

if (fp != stdin) fclose (fp); /* close file if not stdin */

while (list[n]) { /* output stored lines and free allocated mem */
printf ("line[%5zu]: %s\n", n, list[n]);
free (list[n++]);
}

return(0);
}


/** read up to PTRMAX lines from 'fp', allocate/save in 'p'.
* storage is allocated for each line read and pointer
* to allocated block is stored at 'p[x]'. (you should
* add handling of lines greater than LNMAX chars)
*/
char **loadlist (char **p, FILE *fp)
{
int idx = 0; /* index */
char buf[LNMAX] = ""; /* read buf */

while (fgets (buf, LNMAX, fp) && idx < PTRMAX) {

size_t len = strlen (buf); /* get length */

if (buf[len-1] == '\n') /* check for trailing '\n' */
buf[--len] = 0; /* overwrite '\n' with nul-byte */
/* else { handle read of line longer than 200 chars }
*/

if ((p[idx] = malloc (len + 1))) /* allocate storage */
strcpy (p[idx], buf); /* copy buf to storage */
else
return NULL; /* indicate error condition in return */

idx++;
}

return p; /* return pointer to list */
}


最后,在您的任何动态分配内存的代码中,您对分配的任何内存块负有两个责任:(1)始终保留指向该内存块起始地址的指针,因此,(2)在内存块被释放时可以将其释放不再需要。

使用内存错误检查程序来确保您没有在分配的内存块之外/之外进行写操作,试图读取未初始化的值或基于未初始化的值进行跳转,最后确认您已释放了分配的所有内存。

对于Linux, valgrind是通常的选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行程序即可。

查看情况,如果您还有其他问题,请告诉我们。

关于c - C-无法将文本文件中的字符串列表读取并处理到数组中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42032636/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com