ページ 1 / 1
2次元配列の動的確保について質問です。
Posted: 2015年7月19日(日) 05:04
by 山本さん太郎
コード:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
FILE *fp;
int len;
char fn[10] = { "test" };
char text[1000][500];
char A[500];
// textの動的確保
//選んだファイルを読み込む
fp = fopen(fn, "r");
len = 0;
while (fscanf(fp, "%s", text[len]) != EOF)
{
len++;
}
fclose(fp);
len = len / 2;
strcpy(A, text[len]);
}
テキストがあり、その半分の行の文字を配列Aにコピーするようなプログラムの、char text[][]を動的確保したいのですがどのようにすればよろしいでしょうか?
mallocの使い方がいまいち掴めず、困っております。よろしくお願い致します。
Re: 2次元配列の動的確保について質問です。
Posted: 2015年7月19日(日) 09:11
by みけCAT
山本さん太郎 さんが書きました:char text[][]を動的確保したいのですがどのようにすればよろしいでしょうか?
何らかの方法で擬似的な二次元配列を実現する必要があるかもしれません。
例えば、前半にデータへのポインタを置いて、後半にデータを置く領域を確保する、というのはどうでしょうか?
コード:
#include <stdio.h>
#include <stdlib.h>
char** doutekikakuho(int h, int w) {
char** ret = (char**)malloc(sizeof(char*) * h + sizeof(char) * (h * w));
char *buf;
int i;
if (ret == NULL) return NULL;
buf = (char*)(ret + h);
for (i = 0; i < h; i++) ret[i] = buf + w * i;
return ret;
}
int main(void) {
char** text;
int i, j;
text = doutekikakuho(1000, 500);
if (text == NULL) return 1;
for (i = 0; i < 1000; i++) {
for (j = 0; j < 500; j++) {
text[i][j] = (i + j) % 10 + '0';
}
}
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
putchar(text[i][j]);
}
putchar('\n');
}
puts("-----");
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
putchar(text[1000 + i - 10][500 + j - 10]);
}
putchar('\n');
}
free(text);
return 0;
}
Re: 2次元配列の動的確保について質問です。
Posted: 2015年7月19日(日) 09:36
by みけCAT
山本さん太郎 さんが書きました:テキストがあり、その半分の行の文字を配列Aにコピーするようなプログラムの、char text[][]を動的確保したいのですがどのようにすればよろしいでしょうか?
char text[][]を動的確保するのは諦め、リストで領域を管理したほうがいいかもしれません。
コード:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#define CHAR_PER_BUFFER 512
typedef struct strbuffer_tag {
char data[CHAR_PER_BUFFER];
struct strbuffer_tag *next;
} strbuffer_t;
typedef struct list_tag {
char *data;
struct list_tag *next;
} list_t;
/* 1トークン読み込み、その領域を返す */
char *read_text(FILE* fp)
{
strbuffer_t *head = NULL;
strbuffer_t **current = &head;
size_t current_len = 0;
size_t all_len = 0;
size_t i;
char *ret;
int input;
/* 最初の空白を読み飛ばす */
while (isspace(input = getc(fp)) && input != EOF);
if (input == EOF) return NULL;
ungetc(input, fp);
/* 文字列を読み込む */
while (!isspace(input = getc(fp)) && input != EOF) {
/* バッファが無かったら足す */
if (*current == NULL) {
*current = (strbuffer_t*)malloc(sizeof(strbuffer_t));
if (*current == NULL) exit(1);
(*current)->next = NULL;
}
/* 読み込んだ文字を保存する */
(*current)->data[current_len++] = input;
all_len++;
/* バッファがいっぱいになったら先へ進む */
if (current_len >= CHAR_PER_BUFFER) {
current = &(*current)->next;
current_len = 0;
}
}
if (input != EOF) ungetc(input, fp);
/* 読み込んだ文字列をまとめる */
ret = (char*)malloc(sizeof(char) * (all_len + 1));
if (ret == NULL) exit(1);
current = &head;
current_len = 0;
for (i = 0; i < all_len; i++) {
ret[i] = (*current)->data[current_len++];
if (current_len >= CHAR_PER_BUFFER) {
current = &(*current)->next;
current_len = 0;
}
}
ret[all_len] = '\0';
/* バッファを開放する */
while (head != NULL) {
strbuffer_t* next = head->next;
free(head);
head = next;
}
return ret;
}
int main(void)
{
FILE *fp;
int len;
char fn[10] = { "test" };
char *input;
list_t *text = NULL;
list_t **tail = &text;
list_t *text_ptr;
char *A;
int i;
/*選んだファイルを読み込む*/
fp = fopen(fn, "r");
len = 0;
while ((input = read_text(fp)) != NULL)
{
*tail = (list_t*)malloc(sizeof(list_t));
if (*tail == NULL) return 1;
(*tail)->data = input;
(*tail)->next = NULL;
tail = &(*tail)->next;
len++;
}
fclose(fp);
len = len / 2;
for (i = 0, text_ptr = text; i < len; i++)
{
text_ptr = text_ptr->next;
}
A = (char*)malloc(sizeof(char) * (strlen(text_ptr->data) + 1));
if (A == NULL) return 1;
strcpy(A, text_ptr->data);
/* puts(A); */
/* 後片付け */
while (text != NULL) {
text_ptr = text->next;
free(text->data);
free(text);
text = text_ptr;
}
free(A);
return 0;
}
Re: 2次元配列の動的確保について質問です。
Posted: 2015年7月20日(月) 15:09
by かずま
山本さん太郎 さんが書きました:テキストがあり、その半分の行の文字を配列Aにコピーするようなプログラムの、char text[][]を動的確保したいのですがどのようにすればよろしいでしょうか?
fscanf の "%s" で読み込むのは、行ではなく、空白文字で区切られた文字列です。
入力ファイルに空行があったり、1行に複数の文字列があれば、半分の行という
ことにはなりません。
fscanf で読むということで、奇数個の文字列なら真ん中の文字列、
偶数個の文字列なら後半の先頭の文字列ということにします。
それでよろしいでしょうか?
コード:
#include <stdio.h> // FILE, fopen, fclose, fscanf, puts
#include <stdlib.h> // malloc, free
#include <string.h> // strdup
int main(void)
{
FILE *fp;
int len, i;
char *fn = "test";
char **text;
char A[500];
fp = fopen(fn, "r");
if (!fp) return puts("can't open"), 1;
for (len = 0; fscanf(fp, "%499s", A) == 1; len++) ;
text = malloc(sizeof(char*) * len);
if (!text) return puts("out of memory"), 2;
rewind(fp);
for (i = 0; i < len; i++) {
fscanf(fp, "%s", A);
text[i] = strdup(A); // 内部で malloc() を使用
if (!text[i]) return puts("out of memory"), 3;
}
fclose(fp);
strcpy(A, text[len/2]);
puts(A);
for (i = 0; i < len; i++) free(text[i]);
free(text);
return 0;
}
まず、全部を空読みして文字列の個数を取得します。それから、
その個数分の (char *) を確保し、その先頭アドレスを text に入れています。
strdup は文字列の格納に必要なサイズの領域を malloc で確保し、
そこに文字列を入れてくれます。