我正在尝试将未知大小的文本文件读入一个字符数组中。 这是我到目前为止所做的。
name
但是当我读取未知大小的文件时,我不知道如何为输出数组分配大小。 此外,当我输入一个大小的输出说n = 1000时,我得到分段错误。 我是一个非常缺乏经验的程序员,任何指导都表示赞赏:)
文本文件本身在技术上是.csv文件,因此内容如下所示: " 0,0,0,1,0,1,0,1,1,0,1 ..."
答案 0 :(得分:4)
执行此操作的标准方法是使用malloc
分配一些大小的数组,然后开始读取它,如果在用完字符之前用完了数组(也就是说,如果你在填满阵列之前没有达到EOF
,为阵列选择更大的尺寸并使用realloc
使其更大。
这里是读取和分配循环的外观。我选择使用getchar
一次读取一个字符(而不是一次使用fgets
一行)。
int c;
int nch = 0;
int size = 10;
char *buf = malloc(size);
if(buf == NULL)
{
fprintf(stderr, "out of memory\n");
exit(1);
}
while((c = getchar()) != EOF)
{
if(nch >= size-1)
{
/* time to make it bigger */
size += 10;
buf = realloc(buf, size);
if(buf == NULL)
{
fprintf(stderr, "out of memory\n");
exit(1);
}
}
buf[nch++] = c;
}
buf[nch++] = '\0';
printf("\"%s\"", buf);
关于此代码的两点说明:
-1
中的if(nch >= size-1)
进行此操作。答案 1 :(得分:2)
如果我没有添加答案可能是从文本文件中读取未知长度未知行数的最标准方法之一,那将是我的疏忽。在C中,您有两种主要的字符输入方法。 (1)面向字符的输入(即getchar
,getc
等等。)和(2)面向行的输入(即{ {1}},fgets
)。
从这些函数组合中,默认情况下POSIX函数getline
将分配足够的空间来读取任意长度的行(直到系统内存耗尽)。此外,当读取行输入时,面向行的输入通常是正确的选择。
要读取未知数量的行,一般方法是分配预期数量的指针(在指针到char的数组中),然后根据需要重新分配,如果您最终需要更多。如果你想在链表中一起使用字符串指向字符串的复杂性,那很好,但处理一个字符串数组要简单得多。 (如果您的结构具有多个成员而不是单行,则链表更合适)
这个过程很简单。 (1)为某些初始指针(getline
以下LMAX
)分配内存,然后在读取每一行时(2)分配内存以保存该行并将该行复制到该数组({下面使用{1}}(a)分配内存来保存字符串,(b)将字符串复制到新的内存块,返回指向其地址的指针)(将指定的字符串指定为255
)
与任何动态内存分配一样,你负责跟踪分配的内存,保留指向每个已分配内存块的开头的指针(以便以后可以释放它),然后在不再需要时释放内存。 (使用strdup
或类似的内存检查器确认您没有内存错误并释放了您创建的所有内存。
以下是在释放分配用于保存文件的内存之前,简单地读取任何文本文件并将其行打印回array[x]
的方法的示例。一旦您阅读了所有行(或在阅读所有行时),您就可以轻松地将 csv 输入解析为单个值。
注意:下面,当读取valgrind
行时,重新分配stdout
以保持之前的两倍,并继续读取。 (如果要为每一行分配一个新指针,可以将LMAX
设置为array
,但这是处理内存分配的非常低效的方式)选择一些合理的预期起始值,然后重新分配LMAX
当前是标准的重新分配方法,但您可以自由分配您选择的任何大小的其他块。
查看代码,如果您有任何问题,请告诉我。
1
使用/输出强>
2X
内存检查
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LMAX 255
int main (int argc, char **argv) {
if (argc < 2 ) {
fprintf (stderr, "error: insufficient input, usage: %s <filename>\n",
argv[0]);
return 1;
}
char **array = NULL; /* array of pointers to char */
char *ln = NULL; /* NULL forces getline to allocate */
size_t n = 0; /* buf size, 0 use getline default */
ssize_t nchr = 0; /* number of chars actually read */
size_t idx = 0; /* array index for number of lines */
size_t it = 0; /* general iterator variable */
size_t lmax = LMAX; /* current array pointer allocation */
FILE *fp = NULL; /* file pointer */
if (!(fp = fopen (argv[1], "r"))) { /* open file for reading */
fprintf (stderr, "error: file open failed '%s'.", argv[1]);
return 1;
}
/* allocate LMAX pointers and set to NULL. Each of the 255 pointers will
point to (hold the address of) the beginning of each string read from
the file below. This will allow access to each string with array[x].
*/
if (!(array = calloc (LMAX, sizeof *array))) {
fprintf (stderr, "error: memory allocation failed.");
return 1;
}
/* prototype - ssize_t getline (char **ln, size_t *n, FILE *fp)
above we declared: char *ln and size_t n. Why don't they match? Simple,
we will be passing the address of each to getline, so we simply precede
the variable with the urinary '&' which forces an addition level of
dereference making char* char** and size_t size_t *. Now the arguments
match the prototype.
*/
while ((nchr = getline (&ln, &n, fp)) != -1) /* read line */
{
while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
ln[--nchr] = 0; /* strip newline or carriage rtn */
/* allocate & copy ln to array - this will create a block of memory
to hold each character in ln and copy the characters in ln to that
memory address. The address will then be stored in array[idx].
(idx++ just increases idx by 1 so it is ready for the next address)
There is a lot going on in that simple: array[idx++] = strdup (ln);
*/
array[idx++] = strdup (ln);
if (idx == lmax) { /* if lmax lines reached, realloc */
char **tmp = realloc (array, lmax * 2 * sizeof *array);
if (!tmp)
return -1;
array = tmp;
lmax *= 2;
}
}
if (fp) fclose (fp); /* close file */
if (ln) free (ln); /* free memory allocated to ln */
/*
process/use lines in array as needed
(simple print all lines example below)
*/
printf ("\nLines in file:\n\n"); /* print lines in file */
for (it = 0; it < idx; it++)
printf (" array [%3zu] %s\n", it, array[it]);
printf ("\n");
for (it = 0; it < idx; it++) /* free array memory */
free (array[it]);
free (array);
return 0;
}
答案 2 :(得分:1)
-(void)viewWillTransitionToSize:(CGSize)size
withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator {
[self.collectionView.collectionViewLayout invalidateLayout];
[self.collectionView reloadData];
}
使用fseek和ftell获取文本文件的偏移量
答案 3 :(得分:0)
我编写了以下代码来读取未知大小的文件并将每个字符放入缓冲区(对我来说非常适合)。请阅读以下参考资料,以便更好地掌握文件处理:
尝试这样的事情:
char* buffer;
size_t result;
long lSize;
pFile = fopen("CodeSV.txt","r");
if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
// obtain file size:
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);
buffer = malloc(lSize);
// copy the file into the buffer:
result = fread (buffer,1,lSize,pFile);
if (result != lSize) {fputs ("Reading error 2",stderr); exit (3);}
/* the whole file is now loaded in the memory buffer. */
fclose (pFile);
答案 4 :(得分:0)
如果您正在阅读的文件大小不是很大,那么您可以试试这个:
#include<stdio.h>
#include<string.h>
int main()
{
FILE *ptr_file;
char output[10000];
ptr_file =fopen("lol_temp.txt","r");
if (!ptr_file)
return 1;
int bytes_read = fread(output,1,10000,ptr_file);
fclose(ptr_file);
printf("%s",output);
return 0;
}
答案 5 :(得分:0)
使用动态链表比使用数组更好。这里我有一个简单的喜欢列表来存储你从文件中读取的每个字符。既然你说“最终我想把文件读成一个字符串,并操纵字符串并输出修改后的字符串作为一个新的文本文件”我终于创建了一个文件的字符串。我测试了它,所以我猜它应该工作正常:) 您可以将列表的接口和实现分离为单独的文件,甚至可以使用obj。实施文件
#include <stdio.h>
#include <stdlib.h>
typedef char Titem; //just to identify it
// Interface of list
typedef struct node *Tpointer;
typedef struct node {
Titem item;
Tpointer next;
} Tnode;
typedef Tpointer Tlist;
void initialize_list(Tlist *list);
void insert_to_list_end(Tlist *list, Titem data);
void cleanup_list(Tlist *list);
// Implementation of list (only obj file is need in your application)
void initialize_list(Tlist *list) {
*list = NULL;
}
void insert_to_list_end(Tlist *list, Titem data) {
Tpointer newnode, last = *list;
newnode = (Tpointer)malloc(sizeof(Tnode));
newnode->item = data;
newnode->next = NULL;
if (last == NULL){
*list = newnode;
}//first node
else{
while (1) {
if (last->next == NULL) {
last->next = newnode;
break;
}
last = last->next;
}
}
}
void cleanup_list(Tlist *list) {
Tpointer aux1, aux2;
aux1 = *list;
while (aux1 != NULL) {
aux2 = aux1->next;
free(aux1);
printf("\nDeleted"); //for testing purposes
aux1 = aux2;
}
initialize_list(list);
}
#define file_dir "CodeSV.txt"
int main(void){
FILE *fp;
fp = fopen(file_dir, "r");
int counter = 1;
Tlist list;
if (fp) {
initialize_list(&list);
int c;
while ((c = getc(fp)) != EOF){
insert_to_list_end(&list, (char)c);
counter++;
}
fclose(fp);
}
else{ printf("file not found"); return 0; }
//creating a string with what you read
char stringFromFile[counter];
Tlist currentNode = list;
int i;
for (i = 0; i <= counter; i++) {
stringFromFile[i] = currentNode->item;
currentNode = currentNode->next;
if (currentNode == NULL) { break; }
}
printf("WHAT YOU JUST READ: %s", stringFromFile);
/*here you can manipulate the string as you wish. But remember to free the linked list (call cleanup_list) when u're done*/
cleanup_list(&list);
return 1;
}
答案 6 :(得分:0)
如果OP想要进行文本处理和操作行,而不是将整个文件读入1个字符串,请创建行的链接列表。
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LINE_MAXSIZE 65536
typedef struct line_T {
struct line_T *next;
char *data;
size_t length;
} line_T;
line_T *ReadFile(FILE *istream) {
line_T head;
line_T *p = &head;
char *buf = malloc(LINE_MAXSIZE);
assert(buf);
while (fgets(buf, LINE_MAXSIZE, istream)) {
p->next = malloc(sizeof *(p->next));
assert(p->next);
p = p->next;
p->next = NULL;
p->length = strlen(buf);
assert(p->length < LINE_MAXSIZE - 1); // TBD: cope with long lines
p->data = malloc(p->length + 1);
assert(p->data);
memcpy(p->data, buf, p->length + 1);
}
free(buf);
return head.next;
}
unsigned long long CountConsumeData(line_T *p) {
unsigned long long sum = 0;
while (p) {
sum += p->length;
free(p->data);
line_T *next = p->next;
free(p);
p = next;
}
return sum;
}
int main(void) {
const char *fname = "CodeSV.txt";
FILE *istream = fopen(fname, "r");
line_T *p = ReadFile(istream);
fclose(istream);
printf("Length : %llu\n", CountConsumeData(p));
return 0;
}