【问题标题】:Using pointers in 2D arrays在二维数组中使用指针
【发布时间】:2015-09-18 00:11:12
【问题描述】:

我正在尝试将从文件(使用单独的函数)读取的整数数组存储在二维数组中,但我一直遇到分段错误的问题。我知道这是我的指针的问题,但我无法弄清楚我做错了什么。

这是我的函数(取一个整数并将其与从文件中读取的整数进行比较,然后将其存储到我的二维数组中)。

int **getStopTimes(int stop_id) {

int **result = malloc(sizeof(*result)); 
char const* const fileName = "stop_times_test.txt"; 
FILE* txt = fopen(fileName, "r"); 
char line[256];
int count = 0;

while (fgets(line, sizeof(line), txt) != NULL) {    
        int *formattedLine = getStopTimeData(line); //getStopTimeData returns a pointer to an array of ints, memory is allocated in the function
        if (formattedLine[1] == stop_id) {
            result[count] = formattedLine;
            count++;
        }                           
}       
fclose(txt);
return result;  
}

还有我的主要:

int main(int argc, char *argv[]) {
int **niceRow = getStopTimes(21249);
for (int i=0; i<2; i++) { //Only looping 3 iterations for test purposes
    printf("%d,%d,%d,%d\n",niceRow[i][0], niceRow[i][1], niceRow[i][2], niceRow[i][3]);
}
free(niceRow);
return 0;
}

正在调用的getStopTimeData函数(从字符数组中提取某些信息并将它们存储/返回到一个int数组中):

int *getStopTimeData(char line[]) {
int commas = 0;
int len = strlen(line);
int *stopTime = malloc(4 * sizeof(*stopTime)); //Block of memory for each integer
char trip_id[256]; //Temp array to build trip_id string
char stop_id[256]; //Temp array to build stop_id string
int arrival_time; //Temp array to build arrival_time string 
int departure_time; //Temp array to build departure_time string 
int counter;

for(int i = 0; i <len; i++) { 
    if(line[i] == ',')  {
        commas++;
        counter = 0;
        continue;
    }
    switch(commas) { //Build strings here and store them 
        case 0 : 
            trip_id[counter++] = line[i]; 
            if(line[i+1] == ',') trip_id[counter] = '\0';
            break;
        case 1: //Convert to hours past midnight from 24hr time notation so it can be stored as int
            if(line[i] == ':' && line[i+3] == ':') {
            arrival_time = (line[i-2]-'0')*600 + (line[i-1]-'0')*60 + (line[i+1]-'0')*10 + (line[i+2]-'0'); 
            }   
            break;
        case 2 : 
            if(line[i] == ':' && line[i+3] == ':') {
            departure_time = (line[i-2]-'0')*600 + (line[i-1]-'0')*60 + (line[i+1]-'0')*10 + (line[i+2]-'0');
            }       
            break;
        case 3 : 
            stop_id[counter++] =  line[i];
            if(line[i+1] == ',') stop_id[counter] = '\0';
            break;
    }
}
//Assign and convert to ints
stopTime[0] = atoi(trip_id);
stopTime[1] = atoi(stop_id);
stopTime[2] = arrival_time;
stopTime[3] = departure_time;
return stopTime;
}

【问题讨论】:

  • 另外,发布getStopTimeData() 的代码。如果它调用 malloc() 或类似名称,如果错误,它可能会破坏堆,SEGV 会出现在代码的其他位置。
  • 编辑了它——虽然它很长
  • 关于这一行:int **result = malloc(sizeof(*result)); 1) 它根据底层架构分配 4 或 8 个字节。 2) 始终检查 (!=NULL) malloc() 的返回值以确保操作成功
  • 关于这一行:int main(int argc, char *argv[]) 将导致编译器输出 2 个警告,1) 未使用的参数 'argc' 2) 未使用的参数 'argv[]' 建议通过将 main 声明为:@987654328 来修复它@
  • 请为我们人类的可读性和易于理解性,一致地缩进代码(并且不要使用制表符进行缩进,因为每个文字处理器/编辑器的制表位/制表宽度设置不同)建议在每个之后使用 4 个空格左大括号“{”(4 个空格足够宽,即使使用可变宽度字体也可以看到)并且在每个右大括号“}”之前不缩进

标签: c arrays 2d fault


【解决方案1】:

这一行:

int **result = malloc(sizeof(*result));

只为一个指针分配内存。 (*resultint * 类型,所以它是一个指向数据的指针——sizeof 运算符会告诉你指向数据的指针的大小......例如,4 在 32 位架构上)

如果没有看到getStopTimeData() 的代码,我并不完全清楚你想要做什么……但你肯定需要更多内存。如果这个函数确实返回了一个指向某个 ints 的指针,并且它正确地处理了分配,那么您可能需要类似下面的内容:

int result_elements = 32;
int **result = malloc(sizeof(int *) * result_elements);
int count = 0;

[...]
    if (formattedLine[1] == stop_id) {
        if (count == result_elements)
        {
            result_elements *= 2;
            result = realloc(result, result_elements);
        }
        result[count] = formattedLine;
        count++;
    }

添加适当的错误检查,mallocrealloc 可能会在内存不足的情况下返回 (void *)0(又名 null)。

另外,初始分配大小的 32 只是一个疯狂的猜测......根据您的需要调整它(因此它不会浪费大量内存,但对于大多数用例来说已经足够了)

【讨论】:

  • 相应地修改了我的代码并更改了分配大小,但不幸的是,我只是不断收到相同的分段错误。我不确定这意味着什么,但只要我在函数中的任何位置添加 printf,它就会运行得非常好并提供我需要的输出 - 尽管显然这并不能解决问题
  • @PhilO'kelly ...您现在有两个选择。 1.)将您的代码减少到一个最小但可编译的示例,以重现错误 - 您可能会在此过程中自己发现剩余的错误。如果没有,请将其发布在您的问题中。 2.) 使用一些专门定制的工具来查找内存管理问题——如果你在*nix 系统上,尝试valgrind(如果使用gcc 或兼容的编译器,则使用-O0 -g3 编译)。仔细查看输出。如果您仍然无法确定根本问题,请将输出添加到您的问题中。
【解决方案2】:

楼上的答案不错, 只是给你一个建议,尽量避免使用二维数组,而是使用一个简单的数组来存储所有数据,这样可以确保你拥有合并内存。

之后,您可以通过一个简单的技巧访问您的一维数组,将其视为二维数组

考虑你的二维数组有一个 line_size

要像矩阵或二维数组一样访问它,您需要找出给定 x,y 值的一维数组的相应索引

索引 = x + y * 行大小;

反之: 你知道索引,你想找到这个索引对应的x和y。

y = index / line_size;
x = index mod(line_size);

当然,如果您已经知道自己的线条大小,可以使用这个“技巧”

【讨论】:

  • 请注意,此建议非常依赖于您的数据结构。仅当您知道最大 行长度 (在这里称为行大小)并同时确保实际 行长度 不会偏离太多时才有意义.在这种情况下,这是一个很好的建议——否则只会浪费内存。
  • 除此之外,我不同意“尽量避免使用二维数组”。那是因为二维数组可能是 OP 问题的通用 解决方案。软件工程师应该知道一个简单的经验法则:硬件便宜,软件昂贵。因此,如果将 2D 数组“展平”为“简单”数组确实会产生很大的不同,那么值得付出努力。否则,它不是。
  • 其实并不费力,操作起来比双指针简单多了……
  • 不,不是。 C 中的指针语义一开始可能看起来很奇怪,但请更广泛地了解它。选择数据结构(任何语言)应该首先取决于您要建模的真实数据的结构。操作指针的 C 方法使 2D 数组起初看起来很复杂,但是一旦您习惯了所涉及的语法,它并不比例如复杂。 C# 中的List&lt;List&lt;T&gt;&gt;。建模数据结构在技术上不同于它们的自然形式(只要语言允许)是过早的优化
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
  • 1970-01-01
  • 2018-01-04
  • 1970-01-01
  • 2014-06-20
  • 2021-10-09
相关资源
最近更新 更多