首先,是的,这是家庭作业,是的,我一直试图自己解决这个问题,是的,我在SO上阅读了类似的问题,但没有找到我需要的帮助。
我有一个.txt文件,我正在读取一个结构,我真的很难理解sscanf的格式。我现在正处于尝试任何事情的地步,所以我担心如果我做得对,那将是因为我很幸运而不是因为我真的明白我在做什么,这就是希望你好好的人可以提供帮助。
以下是.txt
的示例数据4, Ben Appleseed, 1587 Apple Street, Salt Lake City, UT, 80514
2, Terri Lynn Smith, 1234 Slate Street, Cincinnati, OH, 45242
注意:每个“字段”都用空格,逗号或制表符分隔。一些条目没有中间名,其他每个条目遵循相同的模式。 (如果有人有关于如何处理所有8个字段的线路的建议,我可以提供帮助)
这是我的结构:
typedef struct
{
long lngRecordID;
char strFirstName[50];
char strMiddleName[50];
char strLastName[50];
char strStreet[100];
char strCity[50];
char strState[50];
char strZipCode[50];
} udtAddressType;
这是我填写结构的常规
void AddAddressToArray(char strBuffer[], udtAddressType audtAddressList[])
{
int intIndex = 0;
for (intIndex = 0; intIndex < strBuffer[intIndex]; intIndex += 1)
{
if(sscanf(strBuffer, "%d, %s %s %s %s %s %s %s ",
&audtAddressList[intIndex].lngRecordID,
&audtAddressList[intIndex].strFirstName,
&audtAddressList[intIndex].strMiddleName,
&audtAddressList[intIndex].strLastName,
&audtAddressList[intIndex].strStreet,
&audtAddressList[intIndex].strCity,
&audtAddressList[intIndex].strState,
&audtAddressList[intIndex].strZipCode) != 8)
{
break;
}
}
}
这给了我一个输出:
Address #50 -------------------------
Address ID: 4
First Name: Ben
Middle Name: Appleseed,
Last Name: 1587
Street Address: Apple
City: Street,
State: Salt
Zip Code: Lake
那是不对的。
我不明白如何指定我希望三个地址字段在一行上。 而我所阅读的很多内容只是让我更加困惑。
将文件加载到数组中的函数:
void PopulateAddressList( udtAddressType audtAddressList[])
{
// Declare a file pointer
FILE* pfilInput = 0;
int intResultFlag = 0;
char strBuffer[50] = "";
char chrLetter = 0;
int intIndex = 0;
// Try to open the file for reading
intResultFlag = OpenInputFile("c:\\temp\\Addresses1.txt", &pfilInput);
// Was the file opened?
if (intResultFlag == 1)
{
// Yes, read in records until end of file( EOF )
while (feof(pfilInput) == 0)
{
// Read next line from file
fgets(strBuffer, sizeof(strBuffer), pfilInput);
AddAddressToArray(strBuffer, &audtAddressList[intIndex]);
intIndex += 1;
}
// Clean up
fclose(pfilInput);
}
}
非常感谢任何帮助!
答案 0 :(得分:3)
使用scansets捕获子字符串。 %200[^,],
将扫描所有内容而不是逗号,最多200个字符扫描到char strSub[201];
。根据需要,使用sscanf strSub
来捕获字段。
if(sscanf(strBuffer, "%d, %200[^,], %99[^,], %49[^,], %49[^,],%49s",
&audtAddressList[intIndex].lngRecordID,
strSub,
audtAddressList[intIndex].strStreet,
audtAddressList[intIndex].strCity,
audtAddressList[intIndex].strState,
audtAddressList[intIndex].strZipCode) == 6)
{
//sscan the fields
fields = sscanf ( strSub, "%s%s%s",
audtAddressList[intIndex].strFirstName,
audtAddressList[intIndex].strMiddleName,
audtAddressList[intIndex].strLastName);
if ( fields == 2) {//only two fields
//assume that the second field was for last name so copy middle to last
strcpy (
audtAddressList[intIndex].strLastName,
audtAddressList[intIndex].strMiddleName);
//set middle as blank
audtAddressList[intIndex].strMiddleName[0] = '\0';
}
}
else {
break;
}
答案 1 :(得分:2)
使用feof()
来控制文件循环通常是一种不好的做法。当上一个文件I / O操作设置了文件结束指示符时,feof()
返回一个真值;这通常会在达到文件结束后继续循环时导致错误,但在此指示器由失败的I / O操作设置之前。 Read more about this issue here
您可以使用sscanf()
格式字符串中的扫描集来实现目标。例如,scanset指令%[^,]
将使sscanf()
匹配任何字符,将它们存储在相应参数指示的位置,直到达到,
。当该指令完成后,输入的扫描将以逗号恢复,因此可能需要在此scanset指令后面的格式字符串中放置逗号,以指示sscanf()
匹配并忽略输入之前的输入中的逗号。尝试下一个分配。请注意,在%s
或%[]
指令与scanf()
系列函数一起使用时,指定最大宽度非常重要,以避免缓冲区溢出。
在将名称作为包含(可能是三个)组件的字符串获取后,如果它们存在,则该字符串可以进一步细分为名字,中间名和姓氏。
以下是使用此想法的示例。请注意,feof()
的返回值代替fgets()
,用于确定何时读取了文件的所有行。如果有超过MAX_RECORDS
个条目,则也可以终止读取文件的循环。
首次使用sscanf()
扫描文件中的行时,将检查返回值。如果没有进行六次分配,则输入不符合预期。在这种情况下,记录计数器不会递增,如果该行为空(换行作为第一个字符),则只是跳过它,否则在继续之前会打印错误消息。
成功扫描行输入缓冲区后,name[]
包含记录中的全名。再次使用sscanf()
,这次使用name[]
作为输入字符串。存储返回值并用于确定如何存储fname[]
,mname[]
和lname[]
中包含的字符串(如果适用)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ADDR_FILE "addresses.txt"
#define MAX_RECORDS 1000
#define BUF_SZ 1000
#define NAME_SZ 1000
struct UdtAddress_t
{
long lngRecordID;
char strFirstName[50];
char strMiddleName[50];
char strLastName[50];
char strStreet[100];
char strCity[50];
char strState[50];
char strZipCode[50];
};
int main(void)
{
FILE *fp = fopen(ADDR_FILE, "r");
if (fp == NULL) {
perror("Unable to open file");
exit(EXIT_FAILURE);
}
struct UdtAddress_t records[MAX_RECORDS];
/* Populate structure */
size_t record_ndx = 0;
char buffer[BUF_SZ];
while (record_ndx < MAX_RECORDS &&
fgets(buffer, sizeof buffer, fp) != NULL) {
char name[NAME_SZ];
if (sscanf(buffer, "%ld, %999[^,], %99[^,], %49[^,], %49[^,], %49s",
&records[record_ndx].lngRecordID,
name,
records[record_ndx].strStreet,
records[record_ndx].strCity,
records[record_ndx].strState,
records[record_ndx].strZipCode) != 6) {
/* Skip empty lines and bad input */
if (buffer[0] != '\n') {
fprintf(stderr, "bad input line\n");
}
continue;
}
/* Break name into parts */
char fname[50];
char mname[50];
char lname[50];
int scan_ret = sscanf(name, "%49s %49s %49s", fname, mname, lname);
strcpy(records[record_ndx].strFirstName, fname);
switch(scan_ret) {
case 2:
strcpy(records[record_ndx].strMiddleName, "None");
strcpy(records[record_ndx].strLastName, mname);
break;
case 3:
strcpy(records[record_ndx].strMiddleName, mname);
strcpy(records[record_ndx].strLastName, lname);
break;
default:
strcpy(records[record_ndx].strMiddleName, "None");
strcpy(records[record_ndx].strLastName, "None");
}
++record_ndx;
}
/* Finished with file */
fclose(fp);
/* Show address information */
for (size_t i = 0; i < record_ndx; i++) {
printf("Address %zu -----------------------\n", i+1);
printf("\tAddress ID: %ld\n", records[i].lngRecordID);
printf("\tFirst Name: %s\n", records[i].strFirstName);
printf("\tMiddle Name: %s\n", records[i].strMiddleName);
printf("\tLast Name: %s\n", records[i].strLastName);
printf("\tStreet Address: %s\n", records[i].strStreet);
printf("\tCity: %s\n", records[i].strCity);
printf("\tState: %s\n", records[i].strState);
printf("\tZip Code: %s\n", records[i].strZipCode);
putchar('\n');
}
return 0;
}
这是一个测试文件和一个输出示例:
4, Ben Appleseed, 1587 Apple Street, Salt Lake City, UT, 80514
2, Terri Lynn Smith, 1234 Slate Street, Cincinnati, OH, 45242
42, Cher, 4 Positive Street, Hollywood, CA, 99999
Address 1 -----------------------
Address ID: 4
First Name: Ben
Middle Name: None
Last Name: Appleseed
Street Address: 1587 Apple Street
City: Salt Lake City
State: UT
Zip Code: 80514
Address 2 -----------------------
Address ID: 2
First Name: Terri
Middle Name: Lynn
Last Name: Smith
Street Address: 1234 Slate Street
City: Cincinnati
State: OH
Zip Code: 45242
Address 3 -----------------------
Address ID: 42
First Name: Cher
Middle Name: None
Last Name: None
Street Address: 4 Positive Street
City: Hollywood
State: CA
Zip Code: 99999