[英]Adding file characters to 2d dynamic array C programming
我有一个任务,我们从输入文件中获取内容并将其放入数组中,第一行的数字代表数组的维度。 前 6 个关于文本文件的前 6 行/行,我已经将其放入一维射线中,但之后的字符我必须以已解决的填字游戏的形式将它们放入 5x6 二维数组中(带有空格包括并确保有一个额外的列用于 '\0'so 5x7) 我必须使用 malloc 或 calloc 来制作数组,我的问题是制作矩阵,因为它没有空格或者我得到分段转储。 我首先尝试制作 arrays(两个 arrays - 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 个单词打印为字符串数组,但二维字符数组是我不足的地方。
指甲
炸玉米饼
名称
男人
下一个
能够
分段错误(核心已转储)
这里有很多错误。 我的第一个建议是先让简单的部分工作。 将 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
首先注意奇怪的名字,我希望“单词”是数组或病房,“单词”是您刚刚阅读的那个。
更重要的是,这不是你复制字符串的方式
所以让我们解决这个问题
首先我们需要一个指向单词的指针数组
char *words[N];
我不愿意输入它,因为它不是标准的 c,但你在任何地方都使用它(可变长度 arrays,我的编译器根本不允许它,即使我问得很好)。 但我会做的。
现在我们需要一个字符缓冲区来将当前单词读入
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 是一个很棒的 function,它为字符串分配正确的大小,然后将字符串复制到 malloced 缓冲区,返回一个指向新 mallocd 的指针 memory
该程序中存在几个常见错误。
如果fopen
失败,您会打印一条警告,但仍会继续执行该程序。 您应该在此处退出,或以其他方式处理该事件以防止将来读取失败。
将错误打印到标准错误 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;
}
在 C 中malloc
(或calloc
等)的结果。可以安全地隐式地将void *
提升为任何其他指针类型。
除此之外, sizeof (char)
保证为1
。
/* word = (char *)malloc(sizeof(char) * W); */
word = malloc(W);
在sscanf(inBuf, "%s", &words)
中, &words
是一个char (*)[SIZE]
,这是%s
的错误类型。
不需要&
。 words
的类型为char [SIZE]
,当传递给 function 时,它将衰减为适当的char *
类型。
fgets
、 fscanf
和sscanf
都可能失败。 您应该防范这种情况,以防止程序的 rest 使用不正确的数据。
fgets
在失败时返回NULL
。 *scanf
函数返回执行的成功转换次数( "%s"
是一次转换, "%i%i%i"
是三次)。
if (NULL == fgets(inBuf, SIZE, input))
/* handle this event */;
if (1 != sscanf(inBuf, "%s", words))
/* handle this event */;
*ptr = *words;
不执行字符串复制。 实际上,它将words
的第一个元素复制到ptr
的第一个元素。
ptr = words
将分配指针值。
=
从不用于字符串复制,而是使用strcpy
function 完成复制:
char one[64];
char two[] = "hello world."
strcpy(one, two);
必须注意确保目标缓冲区有足够的空间用于要复制的字符串(包括其 null 终止字节)。
crossword[y][z]
是一个char
。 使用%c
而不是%s
来打印单个字符。
printf(/* "%s" */ "%c", crossword[y][z]);
scanf
说明符%s
跳过前导空格,开始将字符读入其缓冲区,并在遇到更多空格时停止。
sscanf(" e aa", "%s", buffer)
的结果会使buffer
等同于"e"
。 您将无法以这种方式解析其中包含空格的行。
字符集转换说明符 ( %[]
) 可用于克服此限制,因为它允许读取空格。 %[^\n]
将读取所有字符,直到遇到换行符。
请注意,使用不带限制字段宽度说明符的%s
或%[]
与gets
一样是不安全的,因为您可能会溢出缓冲区。
char buffer[16];
if (1 == sscanf(" e aa\n", "%15[^\n]", buffer))
printf("[%s]", buffer); /* => [ e aa] */
话虽如此,简单的解决方案是从输入缓冲区中删除换行符(将其替换为 null 终止字节),如果它存在,并直接使用该缓冲区。
char input[] = " e aa\n";
input[strcspn(input, "\n")] = 0;
crossword
的元素初始化为
crossword[f] = (char *)malloc(N * sizeof(char));
以N
作为第二个维度的长度。 然后他们被访问为
for (int z = 0; z < M; z++) {
/* ... */
crossword[y][z] = token[y][z];
其中z
依赖于不同的边界( M
而不是N
)。 如果N
是5
, M
是6
,这将越界访问 memory 。
通常,不需要所有这些不同的中间缓冲区(和指向缓冲区的指针)。 这可以通过读取每一行的单个缓冲区来完成。
这是一个工作示例,其中包含一些辅助函数以减少代码重复。 该程序的大部分在run
function 中。跟随它应该相对简单:
请注意,输入文件必须在需要填充到指定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 |
+------+
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.