第一个C编程课并开始学习编程。我目前正在学习如何在C中使用文件输入/输出,这是一个学习任务,以帮助理解这个过程。
该任务要求程序使用具有随机美国地址的输入文件,然后按照从最小到最大的顺序输出地址。由于程序现在站立不会崩溃,但我得到一个空的输出文件。我可能知道出了什么问题。我相信我必须告诉程序/函数何时开始读取输入文件,然后何时写入,最后何时关闭文件。可能在某处使用'while'语句?
需要什么以及在何处让此程序将地址输出到文件中?有人可以推荐一个可以添加的功能/声明来实现这个目标吗?
非常感谢您提供帮助,时间和指导,让您的计划有效!
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
@WebIntegrationTest
public class DemoControllerTest {
@Test
public void test() {
get("/lotto").then().assertThat().body("lotto.lottoId", equalTo(5));
}
}
使用的输入:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFF_SIZE 32
#define STRUCT_SIZE 512
struct info {
char name[BUFF_SIZE];
char stAddress[BUFF_SIZE];
char cityAndState[BUFF_SIZE];
char zip[BUFF_SIZE];
};
void selectionSort(struct info *ptrStruct[], int size);
int main(int argc, char *argv[]) {
FILE *fpin, *fpout;
int count, size;
char buffer[512];
struct info *ptrStruct[STRUCT_SIZE];
if (argc != 3) {
printf("Usage: program, inputfile, outputfile\n");
exit(1);
}
if ((fpin = fopen(argv[1], "r")) == NULL) {
printf("Can't open input file\n");
exit(1);
}
if ((fpout = fopen(argv[2], "w")) == NULL) {
printf("Can't open output file\n");
exit(1);
}
for (count = 0; count < STRUCT_SIZE; count++){
ptrStruct[count] = (struct info*) malloc(sizeof(struct info));
if (EOF == scanf("%599[^\n]%*c", buffer)){
free(ptrStruct[count]);
break;
};
strcpy(ptrStruct[count]->name, buffer);
scanf("%511[^\n]%*c", buffer);
strcpy(ptrStruct[count]->stAddress, buffer);
scanf("%511[^\n]%*c", buffer);
strcpy(ptrStruct[count]->cityAndState, buffer);
scanf("%511[^\n]%*c", buffer);
strcpy(ptrStruct[count]->zip, buffer);
}
size = count;
selectionSort(ptrStruct, size);
printf("\n\nLEAST TO GREATEST\n");
for (count = 0; count < size; count++)
{
printf("%s\n", ptrStruct[count]->name);
printf("%s\n", ptrStruct[count]->stAddress);
printf("%s\n", ptrStruct[count]->cityAndState);
printf("%s\n", ptrStruct[count]->zip);
free(ptrStruct[count]);
}
fclose(fpin);
fclose(fpout);
}
void selectionSort(struct info *ptrStruct[], int size)
{
int count1, count2;
int minIndex;
struct info *ptrTemporary;
for (count2 = 0; count2 < size - 1; count2++)
{
minIndex = count2;
for (count1 = count2 + 1; count1 < size; count1++)
{
if (strcmp(ptrStruct[count1]->zip, ptrStruct[minIndex]->zip) < 0)
minIndex = count1;
}
if (minIndex != count2){
ptrTemporary = ptrStruct[count2];
ptrStruct[count2] = ptrStruct[minIndex];
ptrStruct[minIndex] = ptrTemporary;
}
}
}
答案 0 :(得分:1)
第一个main
是int
类型的函数,应该return
为shell的值。虽然并非在所有情况下都是强制性的,但最好初始化所有变量(特别是在您不熟悉C时)。
虽然不是错误,但C的标准编码样式避免使用caMelCase
变量来支持所有小写。参见例如NASA - C Style Guide, 1994
您的阅读循环显示您对如何将输入文件中的数据导入程序感到困惑。您的BUFF_SIZE
常量为32
,但显然已在buffer
返回并硬编码512
,猜测这可能有助于您输入您的程序。 (您无法猜测通往C语言的有效解决方案......)
您最长的输入行是22个字符,因此+1
的{{1}}和'\n'
nul-terminated 字符的+1
表示您最长的行需要'\0'
个字符才能存储。这超出了24
。
您的输入例程要求您一次读取一行。使用面向行的输入函数(如BUFF_SIZE 32
或fgets
)可以更好地完成此操作。此外,您需要确保构成地址的所有4行一起读取并且所有成功读取或不存储任何数据。 (您不希望存储部分地址)。如果你只是检查每一个并且在任何一个上失败(并继续循环),那么getline
,name
,address
和citystate
将会在下一个不同步读。
以一种有意义的方式完成此任务的方法是使用zip
结构的静态实例来构建每个地址。然后,一旦所有成员都包含经过验证的值,请将该信息添加到你的指针数组。
例如,您的读取循环可以完成如下操作:
info
(注意: for (idx = 0; idx < MAXS;) {
int a1, a2, a3, a4;
char buf[MAXB] = "";
struct info tmp = { .name = "" };
if (!fgets (buf, MAXB, fp)) break; /* read/validate lines */
a1 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
!sscanf (buf, "%31[^\n]", tmp.name));
if (!fgets (buf, MAXB, fp)) break;
a2 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
!sscanf (buf, "%31[^\n]", tmp.address));
if (!fgets (buf, MAXB, fp)) break;
a3 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
!sscanf (buf, "%31[^\n]", tmp.citystate));
if (!fgets (buf, MAXB, fp)) break;
a4 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
!sscanf (buf, "%31[^\n]", tmp.zip));
if (a1 || a2 || a3 || a4) continue; /* any error, skip all lines */
if (!(addr[idx] = malloc (sizeof *addr[idx]))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
/* copy tmp to addr[idx] and increment index */
memcpy (addr[idx++], &tmp, sizeof tmp);
}
只检查(1)buf[MAXB - 2] && buf[MAXB - 2] != '\n'
是否已满,以及(2) nul-terminated 字符不是buf
表示简短阅读,并且该行中的字符数超过'\n'
(您的MAXB
- 我不&# 39; t喜欢打字))
至于你的BUFF_SIZE
指针,你只需要一个FILE *
指针。 (您一次不会打开多个流)。至于输出函数,如果你考虑它,你只需要一个输出函数来处理终端(例如fp
文件流)或任何文件(例如stdout
)的输出。因此,您可以根据需要简单地创建单个打印功能。例如:
fp = fopen (somefile, "w")
这只是提供了一种理智的单行输出格式,例如:
/** write 'n' addresses to FILE *fp */
void prnaddr (struct info **addr, int n, FILE *fp)
{
int i;
for (i = 0; i < n; i++)
fprintf (fp, " %-8s %-22s %-20s %s\n", addr[i]->name,
addr[i]->address, addr[i]->citystate, addr[i]->zip);
}
将所有部分放在一起,并注意到当您需要声明多个常量时,您可以简单地使用单个全局 K1, K2 720 Eucalyptus Ave 105 Inglewood, CA 89030
O1, O2 7659 Mckinley Ave Los Angeles, CA 90001
G1, G2 20253 Lorenzana Dr Los Angeles, CA 90005
而不是多个enum
行(并将常量的名称缩短为{ {1}}(最大字符数)和#define
(最大结构数),您可以执行类似以下操作:
MAXC
<强>输入强>
您提供的输入文件已被使用。
示例使用/输出
MAXS
文件输出
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXB = 32, MAXS = 512 };
struct info {
char name[MAXB];
char address[MAXB];
char citystate[MAXB];
char zip[MAXB];
};
void prnaddr (struct info **addr, int n, FILE *fp);
void selectionSort(struct info *addr[], int size);
int main(int argc, char *argv[]) {
int i, idx = 0;
struct info *addr[MAXS] = {NULL};
FILE *fp = NULL;
if (argc != 3) {
printf("Usage: program, inputfile, outputfile\n");
exit(1);
}
if ((fp = fopen(argv[1], "r")) == NULL) {
printf("Can't open input file\n");
exit(1);
}
for (idx = 0; idx < MAXS;) {
int a1, a2, a3, a4;
char buf[MAXB] = "";
struct info tmp = { .name = "" };
if (!fgets (buf, MAXB, fp)) break; /* read/validate lines */
a1 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
!sscanf (buf, "%31[^\n]", tmp.name));
if (!fgets (buf, MAXB, fp)) break;
a2 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
!sscanf (buf, "%31[^\n]", tmp.address));
if (!fgets (buf, MAXB, fp)) break;
a3 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
!sscanf (buf, "%31[^\n]", tmp.citystate));
if (!fgets (buf, MAXB, fp)) break;
a4 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
!sscanf (buf, "%31[^\n]", tmp.zip));
if (a1 || a2 || a3 || a4) continue; /* any error, skip all lines */
if (!(addr[idx] = malloc (sizeof *addr[idx]))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
/* copy tmp to addr[idx] and increment index */
memcpy (addr[idx++], &tmp, sizeof tmp);
}
fclose(fp);
selectionSort(addr, idx);
printf("\nLEAST TO GREATEST\n");
prnaddr (addr, idx, stdout);
if ((fp = fopen(argv[2], "w")) == NULL) {
printf("Can't open output file\n");
exit(1);
}
prnaddr (addr, idx, fp);
fclose(fp);
for (i = 0; i < idx; i++) free(addr[i]);
return 0;
}
/** write 'n' addresses to FILE *fp */
void prnaddr (struct info **addr, int n, FILE *fp)
{
int i;
for (i = 0; i < n; i++)
fprintf (fp, " %-8s %-22s %-20s %s\n", addr[i]->name,
addr[i]->address, addr[i]->citystate, addr[i]->zip);
}
void selectionSort(struct info *addr[], int size)
{
int idx1, idx2;
int minIndex;
struct info *ptrTemporary;
for (idx2 = 0; idx2 < size - 1; idx2++)
{
minIndex = idx2;
for (idx1 = idx2 + 1; idx1 < size; idx1++)
{
if (strcmp(addr[idx1]->zip, addr[minIndex]->zip) < 0)
minIndex = idx1;
}
if (minIndex != idx2){
ptrTemporary = addr[idx2];
addr[idx2] = addr[minIndex];
addr[minIndex] = ptrTemporary;
}
}
}
仔细看看,如果您有任何问题,请告诉我。
答案 1 :(得分:0)
首先,我可以看到您正在使用buffer
扫描scanf
变量中的数据。我至少可以在您的代码中找到以下错误:
您应该使用fscanf
来读取文件fpin
。
您的问题还在于scanf
(fscanf
)格式规范。
此外,在scanf
时,我可以看到您正在将599个字符扫描到buffer
变量中,该变量的长度仅为512.这具有未定义的行为。
一种解决方案:您应该一次一行地逐行读取内容。