【问题标题】:Seg. fault read line-by-line赛格。逐行读取故障
【发布时间】:2016-01-22 23:35:13
【问题描述】:

我正在尝试计算每行出现最多的众数或整数。

我得到一个打印两个值,然后是分段错误。

        for (i = 0; i < count; i++) {

            if (array[i]) {
                int i, j, k, cnt = 1, p, big;
                int b[MAX_NUM] = {0};
                printf("count:%d\n", count);
                for (i = 1; i <= array[i]; i++) {
                    for (j = i + 1; j <= array[i]; j++) {
                        if (array[i] == array[j])
                            printf("cnt:%d\n", cnt);
                        cnt++;
                    }
                    printf("cnt2:%d\n", cnt);
                    b[k] = cnt;
                    k++;
                    cnt = 1;
                }        
                big = b[k];
                p = 1;

                for (i = 2; i <= array[i]; i++) {
                    if (big < b[i]) {
                        big = b[i];
                        p = i;
                    }
                }
                printf("The element that occurs offen is %d\n", array[p]);
                printf("And it has occurred %d times\n", b[p]);
            }
        }
    }
}
}

return 0;
}

编辑:

在我的代码中查看这里的外观。打印的值是文件每一行上的数字,后跟一个空行,如下所示:

1
2
3
4
5
6
5
4
5

14
62
48
14
1
3
5
7
9

123
456
789
1234
5678

34
34
34
34
34

1

1
2
2
2
2
2
3
3
4
4
4
4
5
5
6
7
7
7
1
1

Integers: 9
.....

【问题讨论】:

  • b[k]=cnt; 这一行k 的值是多少? (另外,你能改进一下代码格式吗?)
  • 也许把事情分成不同的函数,这样 gdb 可以告诉你更多。
  • 你的代码真是一团糟!我重新格式化了它,它似乎有太多的右大括号...请学习如何正确缩进和间隔代码,以便其他人可以阅读。你也会帮助自己!
  • 你没有初始化k
  • 我建议使用更具描述性的变量名称。单字符变量名没有说明它代表什么。此外,像array 这样的名称仅表示其类型,而不是它的含义。有用的变量名称是良好的编码风格,有助于您和其他人的可读性。

标签: c segmentation-fault


【解决方案1】:

您在它们隐藏当前定义的内部范围内重新定义 ip。这显然是无意的,因为 for 表达式看起来很错误:

if (array[i]) {
    int i, j, k=1, cnt = 1, p, big;
    //  ^
    //  Redefinition of i.
    //  You should use a different name for the loop index below
    //  Same remark for p, it is safer to not redefine local variables
    //  in inner scopes.  Any { starting a block creates a new scope
    //  in which variables can be defined, or in this case redefined.
     ...
    for (i = 1; i <= array[i]; i++) {
        ...
    for (i = 2; i <= array[i]; i++) {
        ...

在代码的同一区域,您使用k 而不事先初始化。

计算最大出现次数的代码可以放在一个单独的函数中并以这种方式简化:

#include <stdio.h>

// get the number of ocurrences of val in array a of size n
int get_number_of_occurrences(int a[], int n, int val) {
    int cnt = 0, i;

    for (i = 0; i < n; i++) {
        if (a[i] == val)
            cnt++;
    }
    return cnt;
}

// return the index for the number that occurs the most
int get_max_occurrence_index(int a[], int n) {
    int p = 0, cnt, max = 0, i;

    for (i = 0; i < n; i++) {
        cnt = get_number_of_occurrences(a, n, a[i]);
        if (max < cnt) {
            max = cnt;
            p = i;
         }
     }
     return p;
}

int main() {
    int i, n, a[20], max;

    printf("Enter the maximum number of elements\n");
    scanf("%d", &n);
    printf("Enter the elements\n");
    for (i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }
    i = get_max_occurrence_index(a, n);
    max = get_number_of_occurrences(a, n, a[i]);
    printf("The element that occurs most oftenly is %d\n", a[i]);
    printf("And it has occurred %d times\n", max);
    return 0;
}

如果你想在你的原始程序中使用这个逻辑,你应该在你读取文件的每一行使用它,而不是在它只适用于最后一行的末尾。行解析代码也不正确:您将第一个数字的ASCII值作为值,而不是用strtol()解析它。

这是一个更正的版本:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#define MAX_NUM 1000
#define MAX_LINE_LEN 2048
#define N 100

void fatal(const char *msg) {
    printf("%s\n", msg);
    exit(1);
}

int main(int argc, char *argv[]) {
    FILE *fp;
    char filename[100];
    char line[MAX_LINE_LEN];
    char *p;
    int array[MAX_NUM];
    int index, count, max;

    printf("Please enter the file name: \n");

    if (scanf("%99s", filename) != 1) {        
        fatal("Error in entering file.");
    }

    if ((fp = fopen(filename, "r")) == NULL) {
        fatal("Unable to open the file.");
    }

    while ((p = fgets(line, MAX_LINE_LEN, fp)) != NULL) {
        /* skip white space */
        p += strspn(p, " \t\n");
        if (*p == '#' || *p == '\0') {
            /* ignore comment and blank lines */
            continue;
        }
        /* scan and convert the numbers */
        for (count = 0; *p != '\0'; ) {
            if (isdigit((unsigned char)*p)) {
                array[count++] = strtol(p, &p, 10);
                printf("%d\n", array[count]);
            } else {
                /* skip to next space or end of string */
                p += strcspn(p, " \t\n");
            }
            /* skip white space after the number */
            p += strspn(p, " \t\n");
        }

        index = get_max_occurrence_index(array, count);
        max = get_number_of_occurrences(array, count, array[index]);

        printf("The element that occurs most often is %d\n", array[index]);
        printf("And it has occurred %d times\n", max);
    }
    fclose(fp);
    return 0;
}

【讨论】:

  • 如果在作用域中已经有一个i 时声明另一个i,则以前的i 会被新的i“遮蔽”。所以你失去了与之前的i 的关联。不要为新变量使用相同的名称(至少在同一范围内),您将避免此问题。
  • 拜托,我已经有了计算模式的代码,但是我很难用我的数组和文件概念来实现它。我将我的代码用于上述模式,并感谢有关如何集成它的建议。
  • @e0k 请,我已经有计算模式的代码,但是我很难用我的数组和文件概念来实现它。我将我的代码用于上述模式,并感谢有关如何集成它的建议。
  • @Justin_Finland:编写一个函数来计算此计数并将其用于新代码。数组是基于 C 语言的 0,您应该这样编写循环:for (i = 0; i &lt; n; i++) { ... }
  • @chqrlie 这应该可以工作(如果没有指针操作,他可能还不知道)。 Justin_Finland:我建议您在其他练习中多玩一些迭代数组。一个大小为 n 的数组的索引从 0 到 n-1。在我们的学习生涯中,我们都曾犯过同样的错误。
【解决方案2】:

也许我只是看不透你的代码,但我从来没有看到你将文件中的实际数字加载到任何变量或数组中。

您正在加载带有while ((p = fgets(line, MAX_LINE_LEN, fp)) != NULL) { 的行 在该循环中,您将此行分解为标记以计算您有多少个数字。

据我所知,array[count]++; 用于计算每行中有多少个数字。使用索引作为行号。

您应该首先考虑如何将数据转换为可用格式
您可以开始尝试将值加载到二维数组中。
使用第一个维度作为行号,第二个维度作为值。

如果你对自己的代码理解不够透彻,应该从更多的 cmets 入手
你用你的定义和变量做什么。
#define MAX_NUM 1000 //maximum number of lines

int array[MAX_NUM] = {0}; //index refers to line number of file. used to count numbers in each line.

// read file line by line, split every line into tokens to count amount of numbers
while ((p = fgets(line, MAX_LINE_LEN, fp)) != NULL) {
    if (count >= MAX_NUM) {
        fatal("Array error");
    }
    if (line[0] != '#') {
        p = strtok(line, " ");
        while (p != NULL) {
            if (isdigit(*p)) {
                array[count]++;
            }
            p = strtok(NULL, " ");
        }
    }
    count++;
    //printf("COUNT:%D\n", count);
}  

另外选择好的变量名会更好
#define MAX_NUM 1000 -> #define MAX_LINE_NUM 1000

我不知道你的变量 int i, j, k, cnt = 1, p, big; 做了什么。 给他们更好的名字或评论他们。不仅会帮助您,还会帮助您的助手,他们需要了解您打算对他们做什么。

首先我认为您需要有关该模式算法的帮助,所以我先写了这个:
使用非常基本的东西使其尽可能简单。 如果您知道如何将其放入函数中会更干净。 没有使用函数,因为您似乎完全不知道如何使用它们(您应该研究一下)

该算法正在执行以下操作:

  1. 取数组中的第一个数字
  2. 遍历数组,每次找到该数字时,都会增加一个counter
  3. 将号码和计数保存为highesthighestCnt
  4. 对数组中的每个数字重复并覆盖highesthighestCnt 每当count &gt; highestCnt

当有多个出现次数最多的数字时,它只会记住最先计数的数字。如果要返回出现次数最多的所有数字,则需要更改 coude。 可以做一些事情,比如检查count == highestCnt,然后设置一些东西,这样你就知道没有最高计数的单个数字,直到你找到一个计数更高的数字。

#include<stdio.h>

#define sizea 100

int main(void) {
    int array[sizea] = { 1,3,6,8,3,6,7,4,6,9,0,3,5,12,65,3,76,5,3,54,
                         1,3,6,89,3,6,7,4,6,9,0,4,5,12,65,3,76,5,3,54,
                         1,9,6,8,3,45,7,4,6,9,0,89,5,12,65,3,76,5,3,54,
                         6,3,6,8,3,6,7,4,6,9,0,23,5,12,65,3,76,5,3,54,
                         1,3,6,90,3,6,7,4,6,9,0,5,5,12,65,3,76,5,3,54 };

    int number;
    int count = 1;
    int highest = 1;
    int highestCnt = 1;
    int end = sizea - 1;  //end defines at what element in the array the loop will end
    int j;  //j is used to load a number that will be count
    int i;  //i is used run through the array and compare every number the the one that is being count

    for (j = 0; j <= end; j++) {
        number = array[j];  // load a number to count
        count = 1; // start counting at 1

        for (i = j+1; i <= end; i++) {
            // if we find the same number again, we increase the counter
            // then we load the last element into the current array position 
            // then we change decrement "end" by 1
            // this is like throwing out all the numbers we allready count
            // using while instead of if so it will check the last element that was moved to current position as well
            // check for i <= end so it doesnt count twice when the last element equals our number
            while (array[i] == number && i <= end) {
                count++;
                array[i] = array[end];
                end--;
            }
        }
        // if the count of the number is highers the the previus highest, it's obviously our new highest count.
        if (count > highestCnt) {
            highest = number;
            highestCnt = count;
        }

    }
    printf("number: %i, count: %i", highest, highestCnt);
}

【讨论】:

  • 您的最后一段代码正是我想要做的,但我不想让数组具有硬编码值,而是想抓取我的文件的一行并将其存储在一个数组中,然后执行涉及模式的逻辑。请帮忙。 (我注意到数组 [count]++ 之后的 p;在我上面的代码中单独包含了我想要的所有行)
  • @Justin_Finland 就像计算一行中有多少个数字一样。但是不要使用array[count]++; 将你得到的字符串转换为带有atoi() 的整数,然后将其放入数组中。比如:lineNumbers[i++] = atoi(p);
  • @Justin_Finland 我没有足够的声誉来评论另一个答案stackoverflow.com/a/34957905/5778300,但您的array[] 现在包含每行的编号。你用for (count = 0; *p != '\0'; ) { 遍历它,所以count 现在是你的索引。所以只需在 for 循环编辑后打印count+1:我认为它应该是 count+0 因为他在分配值后递增索引
  • 你指的是我对另一个用户说的话:“最初在我上面的代码中,你会看到一行声明: printf("Integers: %d\n", array[i]); .这行代码计算文件每一行的整数个数。所以文件的第一行有9个整数等。我想把它加回你提供的代码中,但不明白在哪里/如何加上那个。”?这就是您要计算文件每一行的整数个数的意思吗?
  • @Justin_Finland 是正确的。我在评论中链接了它
猜你喜欢
  • 2015-02-09
  • 2013-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多