C程序生成伪语言-全局3D数组太大(分段错误)?

时间:2019-05-13 13:25:38

标签: c arrays multidimensional-array segmentation-fault heap

我应该编写一个程序,该程序通过解析现有的英文文本并查看最后打印的两个字母以确定下一个字母可能是什么(第一个被想象为',)以伪英语形式打印文本。 '和'')。对于该任务,我想出了以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

short characters[256][256][256];

int main(int argc, char* argv[]){   
    if(argc<2){
        printf("In addition to the input file and maybe output file, please enter the number of output sentences as a command line argument.\n");
        return 1;
        }

    /*Different approach where I malloced the array instead, same result*/
    /*short ***characters=malloc(256 * sizeof(short**));
    for(int i=0; i<256; i++){
        *characters[i]=malloc(256 * sizeof(short*));
        for(int i2=0; i2<256; i++){
            characters[i][i2]=malloc(256 * sizeof(short**));
            }
        }*/

    /*Read text*/
    char a='.', /*pre-previous character*/
    b=' ', /*previous character*/
    c; /*current character*/
    int n=0;
    while((c=getchar())!=EOF){
        characters[a][b][c]++;
        a=b;
        b=c;
        n++;
        }

    /*Check how many sentences should be printed*/
    int sentences=0, multiplier=1;
    for(int i=0; i<sizeof(argv[1])/8; i++){
        sentences+=argv[1][i]*multiplier;
        multiplier*=10;
        }

    /*Print text*/
    int currentsentences=0, random, p1, p2;
    a='.';
    b=' ';
    while(currentsentences<sentences){
        int uninitialized;
        srand(time(0)+p1+p2+uninitialized); /*adds a bit of entropy*/
        random=rand()%n;
        p1=0;
        for(int i=0; ; i++){
            p2=p1+characters[a][b][i];
            if(random>p1 && random<=p2){
                c=characters[a][b][i];
                p1+=characters[a][b][i];
                break;
                }
            }
        putchar(c);
        if(c=='.' || c=='?' || c=='!')
            currentsentences++;
        a=b;
        b=c;
        }

    return 0;
    }

它编译时没有错误或警告,但是,当我尝试运行该程序时,它总是在输出任何内容之前返回段错误,除非我没有输入足够的命令行参数,在这种情况下,它将输入第一个if子句。这就是为什么我认为它必须对3D数组做一些事情,因为它似乎甚至无法进入第一个循环(如果我让它在此之前打印出东西,则不会)。由于结构如下,因此必须大一些:[pre-previous letter][previous letter][current letter]=how often did this constellation occur。由于我可能不需要较高的ASCII,并且char的范围可能已经足够,我尝试使用char而不是short和128 * 128 * 128的数组-结果相同。以root身份运行它并没有太大变化,增加ulimit也是一样。但是,全局变量不保存在堆中吗?我在上面评论过,malloc()的使用也没有任何改变。我已经在两台机器上尝试过,一台操作系统:X,64位和8GB DDR3,另一台Linux Mint 19.1、64位和32GB DDR4。两者的结果相同(MacOS表示segmentation fault: 11,Linux表示segmentation fault (core dumped))。由于该阵列的已用内存约为33 MB,所以我的RAM也不可能是问题。那么为什么会有段错误?我是否需要为堆分配更多的RAM(我什至认为这是不可能的)?也许这与数组和/或其大小无关吗?

这是程序的最新版本;仍然显示相同的行为:

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

short characters[256][256][256];

int main(int argc, char* argv[]){   

    /*Check if number of sentences was given*/
    if(argc<2){
        printf("In addition to the input file and maybe output file, please enter the number of output sentences as a command line argument.\n");
        return 1;
        }

    /*Different approach with malloc*/
    /*short ***characters=malloc(256 * sizeof(short**));
    for(int i=0; i<256; i++){
        *characters[i]=malloc(256 * sizeof(short*));
        for(int i2=0; i2<256; i++){
            characters[i][i2]=malloc(256 * sizeof(short**));
            }
        }*/

    /*Read input text*/
    int a='.', /*pre-previous character*/
    b=' ', /*previous character*/
    c; /*current character*/
    int n=0;
    for(; (c=getchar())!=EOF; n++){
        characters[a][b][c]++;
        a=b;
        b=c;
        }

    /*Check how many sentences should be printed*/
    int sentences=0, multiplier=1;
    for(int i=strlen(argv[1])-1; i>=0; i--){
        sentences+=(argv[1][i]-'0')*multiplier;
        multiplier*=10;
        }

    /*Print text*/
    int currentsentences=0, random, p1=0, p2=0;
    a='.';
    b=' ';
    srand(time(0));
    while(currentsentences<sentences){
        random=(rand()+p1+p2)%n;
        p1=0;
        for(int i=0; i<256; i++){
            p2=p1+characters[a][b][i]; /*Determine range for character*/
            if(random>p1 && random<=p2){ /*Cheack if random number is in range of character*/
                c=characters[a][b][i];
                p1+=characters[a][b][i];
                break;
                }
            }
        putchar(c);
        if(c=='.' || c=='?' || c=='!')
            currentsentences++;
        a=b;
        b=c;
        }

    return 0;
    }

更新:它显示的一个有趣的行为是,如果在程序的开头添加类似printf(„here“)的内容,则如果第一个„here“会输出if声明(如果输入)。但是,如果不是,程序将在打印任何内容之前返回一个段错误。

更新2:有趣的是,如果您不提供输入文件并手动输入所有内容,它将不会返回段错误,但也永远不会完成。

更新3:该程序现在可以运行,请参见下文。对不起,我造成的所有问题,谢谢您的帮助。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

unsigned int characters[128][128][128];

int main(int argc, char* argv[]){   
     /*Check if input file was given*/
    if(argc<2){
        printf("Please enter an input file as command line argument.\n");
        return 1;
            }

    /*Check for input file, open it*/
    FILE *fp=NULL;
    fp=fopen(argv[1], "r");
    if(!fp){
        printf("Error 404: Input file not found.\n");
        return 404;
        }

    /*Read input text*/
    int a='.';  /*pre-previous character*/
    int b=' ';  /*previous character*/
    int c;      /*current character*/

    while((c=fgetc(fp))!=EOF){
        if(c<127 && c>='\t'){ /*All characters from higher ASCII and system codes ignored. Still uses letters, digits and typical special characters and formatting characters.*/ 
            characters[a][b][c]++;
            a=b;
            b=c;
            }
        }
    fclose(fp);

    /*Check how many sentences should be printed*/
    unsigned int sentences;
    printf("How many sentences do you want to be printed? ");
    scanf("%d", &sentences);

    /*Print text*/
    unsigned int currentsentences=0, random, p1=0, p2=0, n;
    a='.';
    b=' ';
    srand(time(0));
    while(currentsentences<sentences){
        n=0;
        for(int i='\t'; i<127; i++){
            n+=characters[a][b][i];
            }
        random=(rand()+p1+p2+sentences+currentsentences+clock())%n;
        p1=0;
        for(int i='\t'; i<127; i++){    
            p2=p1+characters[a][b][i]; /*Determine range for character in combination with line 58*/
            if(random>=p1 && random<p2 && characters[a][b][i]!=0){ /*Check if random number is in range of character and that character occured in that combination*/
                c=i;
                printf("%c", c);
                characters[a][b][c]++; /*Experimental, language will change over time pseudo-randomly*/
                break;
                }
            p1+=characters[a][b][i];
            }
        if(c=='.' || c=='?' || c=='!')
            currentsentences++;
        a=b;
        b=c;
        }

    printf("\n");

    return 0;
    }

3 个答案:

答案 0 :(得分:4)

主要问题在于代码的这一部分:

    p1=0;
    for(int i=0; ; i++){
        p2=p1+characters[a][b][i];
        if(random>p1 && random<=p2){
            c=characters[a][b][i];
            p1+=characters[a][b][i];
            break;
        }
    }

在这里,您一直在递增i而不检查越界访问。您应该有类似的内容:

if (i >= 255) { // error handling ....};

还要注意,循环中的p1始终为零。

在这部分

random=(rand()+p1+p2)%n;

p1p2未初始化,因此您可能最终得到负数,这显然意味着您从未触及过break语句。换句话说-一个无限循环,您不断增加i(这会导致超出范围的访问)。

作为示例,我将代码更改为:

    for(int i=0; ; i++){
        printf("random=%d p1=%d a=%c b=%c i=%d", random, p1, a, b, i);

并得到如下输出:

...
random=-3 p1=0 a=. b=  i=42484 p2=0
random=-3 p1=0 a=. b=  i=42485 p2=0
random=-3 p1=0 a=. b=  i=42486 p2=0
random=-3 p1=0 a=. b=  i=42487 p2=0
...

请注意,random为负,因此循环永远不会终止。

答案 1 :(得分:4)

在帖子下方的评论中指出了警告,错误和一些非常好的建议。 nota bene

以下评论声明似乎很清楚,

<mat-card>

但是我不清楚在您的以下代码段中正在做什么以实现该目的:

<div>

因此,以下简短代码段建议使用其他方法:

div.Rekrutacja .mat-card {
  background-color: rgb(1, 1, 1);
}

div.Sprzedaż .mat-card {
  background-color: blue;
}

div.Ustawienia .mat-card {
  background-color: yellow;
}

答案 2 :(得分:3)

选择下一个字符的整个逻辑是错误的:

  • 在循环i以检查characters[a][b][i]之后,代码将c发送到输出。那时,c是先前代码中遗留的,或者是characters[a][b][i]中某些i的{​​{1}},这意味着它是在分析过程中看到的三元组计数,而不是应当打印的字符的代码。
  • 用于准备p1p2并将它们与随机数进行比较的代码是荒谬的。该代码应在[0, N )中选择一个随机数,其中 N 是所有字符代码characters[a][b][i]的{​​{1}}的总和,然后选择字符代码i,使c在[cp1)中,其中p2p1等于0的和≤characters[a][b][i] <icp2