[英]Reading formatted strings from file into Array in C
我是C编程语言的新手,并尝试通过仅使用C及其标准库解决来自Project Euler网站的问题来进行改进。 我已经介绍了基本的C基础知识(我认为),函数,指针和一些基本的文件IO,但现在遇到了一些问题。
问题是关于读取名字的文本文件并计算“名称分数”等等,我知道我将要使用的算法,并且具有大部分程序设置,但无法弄清楚如何正确读取文件。
该文件的格式为“ Nameone”,“ Nametwo”,“ billy”,“ bobby”,“ frank” ...我已经搜索并尝试了无数次尝试,但似乎无法将它们作为单个名称读入数组字符串(我认为这是单独存储它们的正确方法吗?)我尝试将sscanf / fscanf与%[^ \\“,]一起使用。它将得到一个新行,这是一个文本文件,同一行上的字符数均超过45,000。
我不确定我对scanf函数的误解,还是对存储字符串数组的误解。 就字符串数组而言,我(认为)已经意识到,当我声明一个字符串数组时,它不会为字符串本身分配内存,这是我需要做的事情。 但是我仍然无法工作。
这是我现在尝试仅读取从命令行输入的一些名称来测试我的方法的代码。
此代码可以输入最大缓冲区大小为(100)的任何字符串:
int main(void)
{
int i;
char input[100];
char* names[10];
printf("\nEnter up to 10 names\nEnter an empty string to terminate input: \n");
for(int i = 0; i < 10; i++)
{
int length = 0;
printf("%d: ", i);
fgets(input, 100, stdin);
length = (int)strlen(input);
input[length-1] = 0; // Delete newline character
length--;
if(length < 1)
{
break;
}
names[i] = malloc(length+1);
assert(names[i] != NULL);
strcpy(names[i], input);
}
}
但是,我根本无法通过读取格式化的字符串来完成此工作。
请建议我如何阅读格式。 我以前在输入缓冲区上使用过sscanf,但效果很好,但是我不觉得我可以在45000+字符行上做到这一点? 我是否可以假设这一点? 这甚至是将字符串读入数组的可接受方法吗?
如果这很长和/或不清楚,很抱歉,已经很晚了,我感到非常沮丧。
感谢任何人和所有人的帮助,我期待着最终成为该站点上的活跃成员!
这里确实有两个基本问题:
实际上,您不会遇到太多这种大小的字符串,但是任何容量的现代计算机都无法轻松处理这一切。 只要这是出于学习目的,然后进行迭代学习。
最简单的第一种方法是将整个行/文件fread()
到适当大小的缓冲区中,然后自行解析。 您可以使用strtok()
来分隔逗号分隔的标记,然后将这些标记传递给去除引号并返回单词的函数。 将单词添加到您的数组。
第二遍,您可以取消strtok()
而只是通过迭代缓冲区并自己拆分逗号来自己解析字符串。
最后但并非最不重要的一点是,您可以编写一个版本,该版本将文件的较小块读入较小的缓冲区并进行解析。 这增加了处理多个读取并管理缓冲区以解决缓冲区末尾的半读令牌的复杂性,依此类推。
在任何情况下,都应将问题分解为多个部分,并从每次改进中学习。
编辑
#define MAX_STRINGS 5000
#define MAX_NAME_LENGTH 30
char* stripQuotes(char *str, char *newstr)
{
char *temp = newstr;
while (*str)
{
if (*str != '"')
{
*temp = *str;
temp++;
}
str++;
}
return(newstr);
}
int main(int argc, char *argv[])
{
char fakeline[] = "\"Nameone\",\"Nametwo\",\"billy\",\"bobby\",\"frank\"";
char *token;
char namebuffer[MAX_NAME_LENGTH] = {'\0'};
char *name;
int index = 0;
char nameArray[MAX_STRINGS][MAX_NAME_LENGTH];
token = strtok(fakeline, ",");
if (token)
{
name = stripQuotes(token, namebuffer);
strcpy(nameArray[index++], name);
}
while (token != NULL)
{
token = strtok(NULL, ",");
if (token)
{
memset(namebuffer, '\0', sizeof(namebuffer));
name = stripQuotes(token, namebuffer);
strcpy(nameArray[index++], name);
}
}
return(0);
}
fscanf("%s", input)
读取一个令牌(由空格包围的字符串)。 您可以扫描输入,直到遇到特定的“输入结束”字符串(例如“!”)为止,也可以等待文件结束信号,这可以通过按C上的“ Ctrl + D”来实现。 Unix控制台,或在Windows控制台上按“ Ctrl + Z”。
第一种选择:
fscanf("%s", input);
if (input[0] == '!') {
break;
}
// Put input on the array...
第二种选择:
result = fscanf("%s", input);
if (result == EOF) {
break;
}
// Put input on the array...
无论哪种方式,一次读取一个令牌时,输入的大小都没有限制。
为什么不搜索巨型字符串中的引号字符呢? 像这样:
#include <stdio.h>
#include <string.h>
int main(void)
{
char mydata[] = "\"John\",\"Smith\",\"Foo\",\"Bar\"";
char namebuffer[20];
unsigned int i, j;
int begin = 1;
unsigned int beginName, endName;
for (i = 0; i < sizeof(mydata); i++)
{
if (mydata[i] == '"')
{
if (begin)
{
beginName = i;
}
else
{
endName = i;
for (j = beginName + 1; j < endName; j++)
{
namebuffer[j-beginName-1] = mydata[j];
}
namebuffer[endName-beginName-1] = '\0';
printf("%s\n", namebuffer);
}
begin = !begin;
}
}
}
您找到第一个双引号,然后是第二个双引号,然后读出名称字符串之间的字符。 然后,根据需要解决这些字符。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.