【发布时间】:2022-01-20 10:51:18
【问题描述】:
我必须从 txt 文件中读取这些行:
1 334.5909245845 161.7809319139
2 397.6446634067 262.8165330708
3 503.8741827107 172.8741151168
4 444.0479403502 384.6491809647
5 311.6137146746 2.0091699828
6 662.8551011379 549.2301263653
7 40.0979030612 187.2375430791
从这里我必须提取每行的第二个和第三个值,因为它们是我的城市的坐标。 我的一段代码如下(我将只显示程序必须读取值的部分):
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdlib.h>
struct city {
double x;
double y;
};
int main(int argc, const char *argv[])
{
FILE *f;
f = fopen(argv[1], "r");
if (f == NULL)
{
printf("cannot read file or inexistant file.\n");
return 1;
}
char lines[2000][150];
int i = 0;
int j = 0;
int c = 0;
// read file's lines
while (c != EOF)
{
while ((c = getc(f)) != EOF && c != '\n')
{
lines[i][j] = c;
j++;
}
lines[i][j] = '\n';
i++;
j = 0;
}
strcpy(lines[i - 2], "\n");
struct city * cities = malloc(sizeof(double) * 10 + 1);
if (cities == NULL)
{
printf("cannot allocate memory");
return 1;
}
int counter = 0;
for (int y = 0; strcmp(lines[y], "\n") != 0; y++)
{
// don't need this check
if (isdigit(lines[y][0]))
{
char * tok;
struct city *new_city = malloc(sizeof(struct city));
if (new_city == NULL)
{
printf("cannot allocate memory");
free(cities);
return 1;
}
//read first number, not used
tok = strtok(lines[y], " ");
//read coordinate x
tok = strtok(NULL, " ");
printf("tok1: %s\n", tok);
new_city -> x = atof(tok);
//read coordinate y
tok = strtok(NULL, " ");
printf("tok2: %s\n", tok);
new_city -> y = atof(tok);
printf("inserted: %lf\n", new_city -> y);
cities[counter] = *new_city;
counter++;
}
}
fclose(f);
我只需打开文件,逐字符读取所有行,然后使用 strtok() 获取写入的坐标(每行的第二个和第三个数字)。问题是我必须将它们存储到我的城市结构的 x 和 y 中,并且正如我在这里所读到的,必须使用 atof(),但它近似于数字,然后它返回分段错误,正如我在这里打印的那样(插入的是城市->y 是近似的但它是错误的,而 tok1 和 tok2 是从文件中读取的两个正确字符串):
tok1: 334.5909245845
tok2: 161.7809319139
inserted: 161.780932
tok1: 397.6446634067
tok2: 262.8165330708
inserted: 262.816533
tok1: 503.8741827107
tok2: 172.8741151168
inserted: 172.874115
tok1: 444.0479403502
tok2: 384.6491809647
zsh: segmentation fault ./Travelling_salesman_problem ch130.tsp
您可以看到比较插入的值和 tok2,插入的值是近似的,然后代码中断。有一种方法不需要更改代码,但只有 atof() 函数具有精确值(因为其余代码有效)?
【问题讨论】:
-
struct city * cities = malloc(sizeof(double) * 10 + 1);这为double类型的 10 个元素分配内存(加上 1 个无用的额外字节)。但在我看来,你想要 N 个struct city类型的元素。 -
@ElenaFranchini 如果您来这里寻求帮助,我们提供建议,请听取我们的建议!我们确实知道我们在说什么,我们给您的这些建议是有效的。你对
\n所做的事情,yano 所问的,不可能是对的。您分配的 10 个 double 绝对不够:您的示例数据将需要 14 个。如果对这些问题的狭隘修复没有解决所有问题,那是因为您的代码有多个问题。但在代码可以工作之前,这些东西肯定也需要修复。 -
如果您计划分配 10 个城市结构,这是错误的做法:
struct city * cities = malloc(sizeof(double) * 10 + 1);— 您应该使用sizeof(cities[0])而不是sizeof(double),而+ 1是巫毒编程.您的崩溃来自于尝试将 7 个城市(14 个双打)存储到一个只能容纳 5 个城市(10 个双打)的数组中。既然知道malloc(),也就知道realloc(),可以安排增量分配数组,每次加倍行数。你需要两个计数器——分配的城市数量和使用的城市数量。 -
语法错误和运行时错误之间有很大的不同,正如您在段错误中看到的那样。您是绝对正确的,编译器并不关心您是否使用
'\n'、'\0'或任何其他字符“终止”您的字符串。但是strcpy和strcmp做 关心。这些函数使用 strings,在 C 中被定义为一个或多个以'\0'结尾的chars 的序列。向str*函数提供格式不正确的字符串会调用undefined behavior,这可能表现为段错误。 -
除了已经提到的问题之外,代码比它需要的要复杂得多。您不需要将整个文件读入二维
lines数组——您可以一次读取一行。您可以通过调用fgets来读取文本行,而不是一次读取一个字符。您不需要每次都分配new_city。我并不是说这些事情中的任何一个都是你的问题的直接原因,但是通过比它们必须的更复杂,它们增加了出现问题的几率,并且它们使得更难发现真正的问题在哪里。
标签: c string type-conversion stdin long-integer