2次元配列の動的確保について質問です。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
山本さん太郎
記事: 5
登録日時: 10年前

2次元配列の動的確保について質問です。

#1

投稿記事 by 山本さん太郎 » 10年前

コード:

#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の使い方がいまいち掴めず、困っております。よろしくお願い致します。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 2次元配列の動的確保について質問です。

#2

投稿記事 by みけCAT » 10年前

山本さん太郎 さんが書きました: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;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 2次元配列の動的確保について質問です。

#3

投稿記事 by みけCAT » 10年前

山本さん太郎 さんが書きました:テキストがあり、その半分の行の文字を配列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;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

かずま

Re: 2次元配列の動的確保について質問です。

#4

投稿記事 by かずま » 10年前

山本さん太郎 さんが書きました:テキストがあり、その半分の行の文字を配列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 で確保し、
そこに文字列を入れてくれます。

閉鎖

“C言語何でも質問掲示板” へ戻る