【问题标题】:Abort trap 6 and text file output中止陷阱 6 和文本文件输出
【发布时间】:2014-12-12 00:29:20
【问题描述】:

此代码用于获取输入文本文件“playlist.txt”,该文件由若干歌曲名称组成,每个歌曲名称各占一行。然后它将播放列表随机播放 7 次,并将随机播放的列表输出到名为“shuffle[day of week]”的文件中。

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

void open(char *playlist, int *size);
void shuffle(char *playlist, int size, char *day);

int main()
{
    char playlist[5000];
    int size = 0;
    open(playlist, &size);
    time_t t;
    srand((unsigned) time(&t));
    shuffle(playlist, size, "Monday");
    shuffle(playlist, size, "Tuesday");
    shuffle(playlist, size, "Wednesday");
    shuffle(playlist, size, "Thursday");
    shuffle(playlist, size, "Friday");
    shuffle(playlist, size, "Saturday");
    shuffle(playlist, size, "Sunday");
}

void open(char *playlist, int *size)
{
    FILE *in = fopen("playlist.txt", "r");
    int i = 0;
    while(fgets(&playlist[i], 30, in) != NULL)
    {
        i++;
        (*size)++;
    }
    fclose(in);
}

void shuffle(char *playlist, int size, char *day)
{
    printf("started %s shuffle\n", day);
    int done = 0;
    int n, i, j;
    int tempsize = size;
    char templist[5000];
    for(i = 0; i < size; i++)
    {
        strcpy(&templist[i], &playlist[i]);
    }
    char newlist [5000];
    for(i = 0; i < size; i++)
    {
        n = rand()%tempsize;
        strcpy(&newlist[i], &templist[n]);
        for(j = n; j < tempsize; j++)
        {
            strcpy(&templist[j], &templist[j+1]);
        }
        tempsize--;
    }
    char listname[20] = "shuffle";
    strcat(listname, day);
    strcat(listname, ".txt");
    FILE *out = fopen(listname, "w");
    for(i = 0; i < size; i++)
    {
        fprintf(out, "%s\n", &newlist[i]);
    }
    fclose(out);
    printf("Finished %s shuffle\n", day);
}

当我运行它时,输出显示周一和周二开始和结束。然后它说星期三开始,但后来我得到了中止陷阱 6。 只创建了星期一和星期二的输出文件,但它们都包含看似随机的字符,它们之间有随机数量的换行符。

我做错了什么? 如何修复中止陷阱?

【问题讨论】:

  • 首先,您应该始终检查来自fopen 的返回值。如果文件无法打开,它将返回 NULL。其次,您应该使用调试器单步执行while(fgets... 循环,同时观察playlist 数组发生的情况。这应该使问题显而易见(或至少其中一个问题)。
  • 关于这一行: void open(char *playlist, int *size); 'open' 是库函数名称。并且代码执行了一个#include ,它具有open() 的原型。所以编译器应该给出一个关于函数签名不匹配的警告,而链接器可能已经给出了一个关于同一个编译对象中的多个同名函数的警告。
  • 文件名;: shuffle + wednesday + .txt + null byte 是21个字节,只分配了20个字节,所以文件名缓冲区溢出。导致未定义的行为和可能的段错误事件
  • 作为播放列表的(字符)列表被随机数分割,这些限制是列表 1 和 0 的总长度。这导致字符串随机分割播放列表名称,包括中间的播放列表名称。可能不是你想要的。

标签: c memory-management fopen abort


【解决方案1】:

除了 user3629249 识别的错误(由于星期三导致文件名溢出一个字节)之外,您用于播放列表和临时列表的数据类型不正确。如果你想要一个包含 5000 首歌曲的播放列表,每首歌曲都由一串文本标识,你需要

char *playlist[5000];  /* an 5000-element array of char *s.  */
char *templist[5000];  /* ditto */

正如你所拥有的,&playlist[i] 是 5000 个元素的字符数组的第 i 个字符,而不是 char *s 的 5000 个元素的数组的第 i 个字符串指针。在您当前的实现中,您会在迭代时逐字节地踩踏您的数据。如果更改为 char * 数组,则将逐个指针步进。

但是!请注意,您声明了一个固定大小的数组(5000 个元素),但您在任何地方都没有验证您不会尝试写入超过 5000 个元素,这也可能导致 Abort(信号 6)或 Segfault(信号 9 )。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-27
    • 1970-01-01
    • 2014-12-13
    相关资源
    最近更新 更多