将文件字符添加到2D动态阵列C编程

发布于 2025-01-17 22:41:58 字数 2031 浏览 4 评论 0原文

我有一个作业,我们从输入文件中获取内容并将其放入 arrys 中 第一行的数字表示数组的维度。前 6 个涉及文本文件中的前 6 行/行,我已将其放入一维射线中,但之后的字符我必须将它们以已解决的填字游戏的形式放入 5x6 二维数组中(带有空格)包含并确保有一个额外的列“\0”,所以 5x7) 我必须使用 malloc 或 calloc 来制作数组,我的问题是制作矩阵,因为它没有得到空格,或者我得到了分段转储。我尝试先创建数组(两个数组 - W 字符串的一维数组和 NxM 的二维字符数组)并确保元素位于矩阵中,但就像我说的那样,我不断收到分段转储。我不知道如何做到这一点。 txt 文件:

6 5 6
nail
taco
name
men
next
can
 next 
namect
  e aa
  n nc
 nail

这是到目前为止我的代码:

void freeMatrix(char **matrix, int r, int c);

int main(int argc, char **argv)
{
    int W, N, M;
    char inBuf[SIZE], words[SIZE], crosswords[SIZE];
    char *word;
    char *outp;
    FILE *input;
    // FILE *output;

    if (argc != 2)
    {
        printf("Error, please input the filenames\n");
        exit(-1);
    }

    if ((input = fopen(argv[1], "r")) == NULL)
    {
        printf("Error, the file %s cannot be opened\n", argv[1]);
    }
    fgets(inBuf, SIZE, input);
    sscanf(inBuf, "%i%i%i", &W, &N, &M);
    word = (char *)malloc(sizeof(char) * W);
    char *crossword[N];
    char *ptr = word;
    char token[N][M];

    for (int x = 0; x < W; x++)
    {
        fgets(inBuf, SIZE, input);
        sscanf(inBuf, "%s", &words);
        printf("%s\n", words);
        *ptr = *words;
    }

    for (int f = 0; f < N; f++)
    {
        crossword[f] = (char *)malloc(N * sizeof(char));
    }
    for (int y = 0; y < N; y++)
    {
        for (int z = 0; z < M; z++)
        {
            fscanf(input, "%c", &token[y][z]);
            crossword[y][z] = token[y][z];
            printf("%s", crossword[y][z]);
        }
        printf("\n");
    }

    fclose(input);
    free(word);
    freeMatrix(crossword, N, M);
    return 0;
}

void freeMatrix(char **matric, int r, int c)
{
    for (int i = 0; i < r; i++)
    {

        free(matric[i]);
    }

    free(matric);
}

我希望以与文本文件设置相同的方式使用矩阵中的各个字符打印填字游戏。导致分段错误。它将前 6 个单词很好地打印为字符串数组,但二维字符数组是我的不足之处。

指甲炸

玉米饼

名称

男士

下一个

可以

分段错误(核心已转储)

I have an assignment where we take in the contents from an input file and put it into arrys
the numbers on the first line represent the dimensions for the array. the first 6 regards the first 6 rows/lines on the text file, which i have put in a one dimensional ray but the characters after that i have to put them in a 5x6 2d array in the form of a solved crossword (with the spaces included and making sure to have a n extra column for '\0'so 5x7) I have to use malloc or calloc to make the array and my issue is making the matrix as it doesnt get the spaces or i get a segmentation dump. Im trying to make the arrays first(two arrays - one dimensional array of W strings and a 2d array of characters NxM) and make sure the elements are in the matrix but like i said i keep getting a segmentation dump. Im at a loss as to how to do this.
txt file:

6 5 6
nail
taco
name
men
next
can
 next 
namect
  e aa
  n nc
 nail

here's my code so far:

void freeMatrix(char **matrix, int r, int c);

int main(int argc, char **argv)
{
    int W, N, M;
    char inBuf[SIZE], words[SIZE], crosswords[SIZE];
    char *word;
    char *outp;
    FILE *input;
    // FILE *output;

    if (argc != 2)
    {
        printf("Error, please input the filenames\n");
        exit(-1);
    }

    if ((input = fopen(argv[1], "r")) == NULL)
    {
        printf("Error, the file %s cannot be opened\n", argv[1]);
    }
    fgets(inBuf, SIZE, input);
    sscanf(inBuf, "%i%i%i", &W, &N, &M);
    word = (char *)malloc(sizeof(char) * W);
    char *crossword[N];
    char *ptr = word;
    char token[N][M];

    for (int x = 0; x < W; x++)
    {
        fgets(inBuf, SIZE, input);
        sscanf(inBuf, "%s", &words);
        printf("%s\n", words);
        *ptr = *words;
    }

    for (int f = 0; f < N; f++)
    {
        crossword[f] = (char *)malloc(N * sizeof(char));
    }
    for (int y = 0; y < N; y++)
    {
        for (int z = 0; z < M; z++)
        {
            fscanf(input, "%c", &token[y][z]);
            crossword[y][z] = token[y][z];
            printf("%s", crossword[y][z]);
        }
        printf("\n");
    }

    fclose(input);
    free(word);
    freeMatrix(crossword, N, M);
    return 0;
}

void freeMatrix(char **matric, int r, int c)
{
    for (int i = 0; i < r; i++)
    {

        free(matric[i]);
    }

    free(matric);
}

I expected a crossword to be printed with the individual characters in the matrix the same way the text file has it set up. A segmentation error resulted. It prints the first 6 words fine as an array of strings but the 2d array of characters is where i fall short.

nail

taco

name

men

next

can

Segmentation fault (core dumped)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

网名女生简单气质 2025-01-24 22:41:58

这里有很多事情是错误的。我的第一个建议是先让简单的部分开始工作。将这 6 个字读入一个数组,然后打印出来。首先让其发挥作用。 (目前这在您的代码中不起作用,您不会保存单词然后在任何地方输入)。现在出了什么问题,

fgets(inBuf, SIZE, input); // ok
sscanf(inBuf, "%i%i%i", &W, &N, &M); //ok

下面这个词的目的是什么?它是一个 6 个字符的数组。似乎没有意义,因为 6 是单词的数量,而不是单词的长度

word = (char *)malloc(sizeof(char) * W);
char *crossword[N];
char *ptr = word; 
//  char token[N][M]; <<<< dont need this yet

// ok this loop read W words from the input file.
for (int x = 0; x < W; x++)
{
    fgets(inBuf, SIZE, input); // good
    sscanf(inBuf, "%s", &words); // you could have fscanf directly but ok
    printf("%s\n", words); // print it
    *ptr = *words;  // meaningless line
}

我认为最后一行以某种方式试图将您刚刚读到的单词复制到缓冲区“word”中,因为您做了 *ptr = word 早先

首先注意奇怪的名称,我希望“words”是数组或病房,“word”是您刚刚读到的那个。

更重要的是,这不是你复制字符串的方式

所以让我们解决这个问题

首先我们需要一个指向单词的指针数组

 char *words[N];

我不愿意输入它,因为它不是标准的c,但你在任何地方都使用它(可变长度数组,我的编译器不允许它在所有,即使我问得很好)。但我会做的。

现在我们需要一个字符缓冲区来读取当前单词,

 char word[SIZE]; // get rid of old word and words

让我们做一些阅读

 // get rid of old word and words
 char word[SIZE]; 
 char *words[N]; 

for (int x = 0; x < W; x++)
{
    fgets(inBuf, SIZE, input);
    sscanf(inBuf, "%s", &word);
    words[x] = strdup(word);
}

现在

for (int x = 0; x < W; x++)
{
      printf("%s\n", words[x];
}

来证明我们确实有数据

在继续下一节之前得到所有的工作

PS,strdup 是一个很棒的函数,它可以为单词分配正确的大小string,然后将字符串复制到 mallocd 缓冲区,返回指向新 mallocd 内存的指针

A lot of things wrong here. My first suggestion is just to get the easy bit working first. Read in the 6 words into an array and then print them out. Get that working first. (that isnt working in your code at the moment, you do not save the words then get entered anywhere). Here is whats wrong at the moment

fgets(inBuf, SIZE, input); // ok
sscanf(inBuf, "%i%i%i", &W, &N, &M); //ok

what is the purpose of word below? It is an array of 6 characters. There seems no point to it since 6 is the number of words, not the length of them

word = (char *)malloc(sizeof(char) * W);
char *crossword[N];
char *ptr = word; 
//  char token[N][M]; <<<< dont need this yet

// ok this loop read W words from the input file.
for (int x = 0; x < W; x++)
{
    fgets(inBuf, SIZE, input); // good
    sscanf(inBuf, "%s", &words); // you could have fscanf directly but ok
    printf("%s\n", words); // print it
    *ptr = *words;  // meaningless line
}

I think that last line is somehow trying to copy the word you just read into the buffer 'word' given that you did *ptr = word earlier

First note the odd names, I would expect 'words' to be the array or wards and 'word' to be the one you just read.

More importantly thats not how you copy strings

So lets fix this

First we need an array of pointers to words

 char *words[N];

I am reluctant to type that because its not standard c but you use it every where (Variable length arrays, my compiler does not allow it at all, even if I ask really nicely). But I will do it.

now we need a char buffer to read the current word into

 char word[SIZE]; // get rid of old word and words

now lets do some reading

 // get rid of old word and words
 char word[SIZE]; 
 char *words[N]; 

for (int x = 0; x < W; x++)
{
    fgets(inBuf, SIZE, input);
    sscanf(inBuf, "%s", &word);
    words[x] = strdup(word);
}

now

for (int x = 0; x < W; x++)
{
      printf("%s\n", words[x];
}

to prove we actually have the data

get all that workinig before moving on to the next section

PS, strdup is a wonderful function that mallocs the correct size for the string and then copies the string to the malloced buffer, returnig a pointer to the newly mallocd memory

作死小能手 2025-01-24 22:41:58

该程序中存在一些常见的错误。


如果Fopen失败,则打印警告,但无论如何继续使用该程序。您应该在此处退出,或以其他方式处理事件,以防止将来的阅读失败。

将错误打印到标准误差流也将是谨慎的。

if ((input = fopen(argv[1], "r")) == NULL)
{
    /* printf("Error, the file %s cannot be opened\n", argv[1]); */
    fprintf(sterr, "Failed to open [%s].\n", argv[1]);
    return EXIT_FAILURE;
}

施放malloc的结果(或calloc等)。其他指针类型。

除此之外,保证sizeof(char)1

/* word = (char *)malloc(sizeof(char) * W); */
word = malloc(W);

sscanf(inbuf,“%s”,&amp; words)&amp; wordschar> char(*)[size],哪个是%s的错误类型。

不需要&amp;单词是类型char [size],将 decay 转换给适当的char *输入到功能。


fgetsfscanfsscanf都可能失败。您应该防止这种情况,以防止其余程序使用不正确的数据。

fgets返回null失败。 *scanf函数返回成功转换的数量执行(“%s”是一种转换,“%i%i%i%i i i “是三个)。

if (NULL == fgets(inBuf, SIZE, input))
    /* handle this event */;
    
    
if (1 != sscanf(inBuf, "%s", words))
    /* handle this event */;

*ptr = *单词;不执行字符串副本。实际上,它将单词的第一个元素复制到ptr的第一个元素。

ptr =单词将分配指针值。

=从不用于字符串复制,而是使用strcpy函数进行复制:

char one[64];
char two[] = "hello world."
strcpy(one, two);

必须注意确保目标缓冲区在to-to-to-被填充的字符串(包括其空的终止字节)。


填字游戏[y] [z]char。使用%c不是%s打印单个字符。

printf(/* "%s" */ "%c", crossword[y][z]);

scanf指定器%s跳过领先的空格,开始将字符读取到其缓冲区中,并在遇到更多空间时停止。

sscanf(“ e aa”,“%s”,buffer)的结果将具有buffer等效于“ e”。您将无法使用其中的空间来解析线路。

字符集转换说明器(%[])可用于克服此限制,因为它允许阅读空格。 %[^\ n]将读取所有字符,直到它遇到新线为止。

请注意,使用%s%[]而无需限制字段宽度指定不安全,因为get> get,您可以溢出缓冲区。

char buffer[16];
if (1 == sscanf("  e aa\n", "%15[^\n]", buffer))
    printf("[%s]", buffer); /* => [  e aa] */

话虽如此,简单的解决方案是只要从输入缓冲区中删除新线(用零件终止字节),如果存在,则直接使用该缓冲区。

char input[] = "  e aa\n";
input[strcspn(input, "\n")] = 0;

填字游戏的元素

crossword[f] = (char *)malloc(N * sizeof(char));

n作为第二维度的长度进行初始化。然后将它们访问为

for (int z = 0; z < M; z++) {
    /* ... */
    crossword[y][z] = token[y][z];

z依赖于其他界限(m而不是n)。如果n5,并且m6,则将访问内存。


通常,不需要所有这些不同的中间缓冲液(以及缓冲区的指针)。这可以使用单个缓冲区来读取每一行。

这是一个具有一些辅助功能的工作示例,以减少代码重复。该程序的大部分位于运行函数中。遵循的内容应该相对简单:

  1. 阅读标题信息
  2. 为我们的 word_count 指示器分配足够的空间。
    1. 读取 word_count 行,每个行:
      1. 为此分配足够的内存
      2. 将字符串复制到此分配的内存
  3. 分配足够的内存,以 rows * cols 矩阵
    1. 读取行,每个行:
      1. 将每个字节从字符串(不包括空字节)复制到矩阵中的正确行和列
  4. 使用数据(显示)
  5. 免费所有分配

,请注意,输入文件必须包含在需要填充到指定<<<的行上的落后空间代码> cols 长度(如果超大,则会发生截断)。

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

/* output formatted message to stderr and exit program unsuccessfully */
static void panic(const char *fmt, ...) {
    va_list args;

    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    fputc('\n', stderr);
    va_end(args);

    exit(EXIT_FAILURE);
}

/* read a line of input into a size limited buffer; removes newline character */
static size_t read_file_line(char *buffer, int size, FILE *file) {
    if (!fgets(buffer, size, file))
        panic("Could not read user input.");

    size_t length = strcspn(buffer, "\n");

    buffer[length] = 0;

    return length;
}

/* panic unless memory allocation successful */
static void *palloc(size_t bytes) {
    void *p = malloc(bytes);

    if (!p)
        panic("Could not allocate %zu bytes.", bytes);

    return p;
}

static void print_matrix(size_t r, size_t c, char (*m)[r][c]) {
    putchar('+');
    for (size_t i = 0; i < c; i++)
        putchar('-');
    puts("+");

    for (size_t i = 0; i < r; i++) {
        putchar('|');
        for (size_t j = 0; j < c; j++)
            putchar((*m)[i][j]);
        puts("|");
    }

    putchar('+');
    for (size_t i = 0; i < c; i++)
        putchar('-');
    puts("+");
}

static void run(FILE *file) {
    size_t word_count;
    size_t rows;
    size_t cols;

    char input[128];

    /* read our header information */
    read_file_line(input, sizeof input, file);

    if (3 != sscanf(input, "%zu%zu%zu", &word_count, &rows, &cols))
        panic("Could not read file header.");

    /* allocate the word list, read and allocate each word */
    char **words = palloc(sizeof *words * word_count);

    for (size_t i = 0; i < word_count; i++) {
        size_t len = read_file_line(input, sizeof input, file);

        words[i] = palloc(len + 1);
        strcpy(words[i], input);
    }

    /* allocate and read our matrix */
    char (*matrix)[rows][cols] = palloc(sizeof *matrix);

    for (size_t i = 0; i < rows; i++) {
        size_t len = read_file_line(input, sizeof input, file);

        if (len < cols)
            panic("Insufficient column data: Required %zu, Read %zu", cols, len);

        for (size_t j = 0; j < cols; j++)
            (*matrix)[i][j] = input[j];
    }

    /* display our input */
    for (size_t i = 0; i < word_count; i++)
        printf("WORD: %s\n", words[i]);

    print_matrix(rows, cols, matrix);

    /* free the memory */
    for (size_t i = 0; i < word_count; i++)
        free(words[i]);
    free(words);
    free(matrix);
}

int main(int argc, char **argv) {
    if (argc != 2)
        panic("usage: %s FILENAME", argv[0]);

    FILE *file = fopen(argv[1], "r");

    if (!file)
        panic("Could not open file [%s].", argv[1]);

    run(file);
    fclose(file);
}

Stdout

WORD: nail
WORD: taco
WORD: name
WORD: men
WORD: next
WORD: can
+------+
| next |
|namect|
|  e aa|
|  n nc|
| nail |
+------+

There are several common mistakes present in this program.


If fopen fails, you print a warning but continue with the program anyway. You should exit here, or otherwise handle the event to prevent future reads from failing.

It would also be prudent to print errors to the standard error stream.

if ((input = fopen(argv[1], "r")) == NULL)
{
    /* printf("Error, the file %s cannot be opened\n", argv[1]); */
    fprintf(sterr, "Failed to open [%s].\n", argv[1]);
    return EXIT_FAILURE;
}

Casting the result of malloc (or calloc, etc.) is not necessary in C. A void * can be safely and implicitly promoted to any other pointer type.

In addition to this, sizeof (char) is guaranteed to be 1.

/* word = (char *)malloc(sizeof(char) * W); */
word = malloc(W);

In sscanf(inBuf, "%s", &words), &words is a char (*)[SIZE], which is the wrong type for %s.

The & is not needed. words is of type char [SIZE], which will decay to the appropriate char * type when passed to a function.


fgets, fscanf, and sscanf can all fail. You should guard against this to prevent the rest of your program working with incorrect data.

fgets returns NULL on failure. *scanf functions return the number of successful conversions performed ("%s" is one conversion, "%i%i%i" is three).

if (NULL == fgets(inBuf, SIZE, input))
    /* handle this event */;
    
    
if (1 != sscanf(inBuf, "%s", words))
    /* handle this event */;

*ptr = *words; does not perform a string copy. Actually, it copies the first element of words to the first element of ptr.

ptr = words would assign the pointer value.

= is never used for string copying, and instead, copying is done with the strcpy function:

char one[64];
char two[] = "hello world."
strcpy(one, two);

Care must be taken to ensure that the destination buffer has enough space for the to-be-copied string (including its null terminating byte).


crossword[y][z] is a char. Use %c not %s to print single characters.

printf(/* "%s" */ "%c", crossword[y][z]);

The scanf specifier %s skips leading whitespace, begins reading characters into its buffer, and stops when it encounters more whitespace.

The result of sscanf(" e aa", "%s", buffer) would have buffer be equivalent to "e". You will not be able to parse the lines with spaces in them this way.

The character set conversion specifier (%[]) can be used to overcome this limitation, as it allows reading whitespace. %[^\n] will read all characters until it encounters a newline.

Note that using either %s or %[] without a limiting field width specifier is unsafe as gets, as you can overflow the buffer.

char buffer[16];
if (1 == sscanf("  e aa\n", "%15[^\n]", buffer))
    printf("[%s]", buffer); /* => [  e aa] */

With that said, the simple solution is to just remove the newline from the input buffer (replace it with the null terminating byte), if it exists, and use that buffer directly.

char input[] = "  e aa\n";
input[strcspn(input, "\n")] = 0;

The elements of crossword are initialized as

crossword[f] = (char *)malloc(N * sizeof(char));

with N as the length of the second dimension. They are then accessed as

for (int z = 0; z < M; z++) {
    /* ... */
    crossword[y][z] = token[y][z];

where z relies on a different bound (M instead of N). If N is 5, and M is 6, this will access memory out of bounds.


In general, there is no need for all these different, intermediate buffers (and pointers to buffers). This can be done with a single buffer for reading each line.

Here is a working example with some helper functions to reduce code repetition. The bulk of the program is in the run function. It should be relatively straightforward to follow along:

  1. read the header information
  2. allocate enough space for our word_count pointers to strings.
    1. read word_count lines, for each:
      1. allocate enough memory for it
      2. copy the string to this allocated memory
  3. allocate enough memory for a rows * cols matrix
    1. read rows lines, for each:
      1. copy each byte from the string (excluding the null byte) to the correct row and column in the matrix
  4. use the data (display it)
  5. free all allocations

Note that the input file must contain trailing whitespace on lines that require padding up to the specified cols length (truncation occurs if oversized).

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

/* output formatted message to stderr and exit program unsuccessfully */
static void panic(const char *fmt, ...) {
    va_list args;

    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    fputc('\n', stderr);
    va_end(args);

    exit(EXIT_FAILURE);
}

/* read a line of input into a size limited buffer; removes newline character */
static size_t read_file_line(char *buffer, int size, FILE *file) {
    if (!fgets(buffer, size, file))
        panic("Could not read user input.");

    size_t length = strcspn(buffer, "\n");

    buffer[length] = 0;

    return length;
}

/* panic unless memory allocation successful */
static void *palloc(size_t bytes) {
    void *p = malloc(bytes);

    if (!p)
        panic("Could not allocate %zu bytes.", bytes);

    return p;
}

static void print_matrix(size_t r, size_t c, char (*m)[r][c]) {
    putchar('+');
    for (size_t i = 0; i < c; i++)
        putchar('-');
    puts("+");

    for (size_t i = 0; i < r; i++) {
        putchar('|');
        for (size_t j = 0; j < c; j++)
            putchar((*m)[i][j]);
        puts("|");
    }

    putchar('+');
    for (size_t i = 0; i < c; i++)
        putchar('-');
    puts("+");
}

static void run(FILE *file) {
    size_t word_count;
    size_t rows;
    size_t cols;

    char input[128];

    /* read our header information */
    read_file_line(input, sizeof input, file);

    if (3 != sscanf(input, "%zu%zu%zu", &word_count, &rows, &cols))
        panic("Could not read file header.");

    /* allocate the word list, read and allocate each word */
    char **words = palloc(sizeof *words * word_count);

    for (size_t i = 0; i < word_count; i++) {
        size_t len = read_file_line(input, sizeof input, file);

        words[i] = palloc(len + 1);
        strcpy(words[i], input);
    }

    /* allocate and read our matrix */
    char (*matrix)[rows][cols] = palloc(sizeof *matrix);

    for (size_t i = 0; i < rows; i++) {
        size_t len = read_file_line(input, sizeof input, file);

        if (len < cols)
            panic("Insufficient column data: Required %zu, Read %zu", cols, len);

        for (size_t j = 0; j < cols; j++)
            (*matrix)[i][j] = input[j];
    }

    /* display our input */
    for (size_t i = 0; i < word_count; i++)
        printf("WORD: %s\n", words[i]);

    print_matrix(rows, cols, matrix);

    /* free the memory */
    for (size_t i = 0; i < word_count; i++)
        free(words[i]);
    free(words);
    free(matrix);
}

int main(int argc, char **argv) {
    if (argc != 2)
        panic("usage: %s FILENAME", argv[0]);

    FILE *file = fopen(argv[1], "r");

    if (!file)
        panic("Could not open file [%s].", argv[1]);

    run(file);
    fclose(file);
}

stdout:

WORD: nail
WORD: taco
WORD: name
WORD: men
WORD: next
WORD: can
+------+
| next |
|namect|
|  e aa|
|  n nc|
| nail |
+------+
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文