質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

コンパイル

コンパイルとは、プログラミング言語のテキストソース(ソースコード)をコンピュータ上で実行可能な形式(オブジェクトコード)に変換することをいいます

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

3回答

3604閲覧

C言語 mallocを使わずに動的に領域を確保することは可能か?

Kchan_01

総合スコア110

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

コンパイル

コンパイルとは、プログラミング言語のテキストソース(ソースコード)をコンピュータ上で実行可能な形式(オブジェクトコード)に変換することをいいます

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

1クリップ

投稿2020/03/03 02:57

編集2020/03/03 03:06

C言語の勉強をしています。
下記は、受け取った文字列を逆にして出力するプログラムです。
mallocを使用せずに、文字数を変数に格納して、それを配列の宣言に利用しています。
私の環境ではコンパイルして動きますが、このような書き方は問題ないのでしょうか。

c

1#include <stdio.h> 2 3char *ft_strrev(char *str) 4{ 5 6 int len = 0; 7 char *strrev; 8 9 // 受け取った文字列の文字数をカウントする 10 while(str[len] != '\0'){ 11 len++; 12 } 13 14 // 文字数の分の配列を宣言し、領域を確保する。 15 // 確保した配列のアドレスを変数に渡す。 16 char tmp[len]; 17 strrev = tmp; 18 int i =0; 19 20 // 配列に逆順に文字を格納していく。 21 while(len > 0){ 22 strrev[i] = str[len-1]; 23 i++; 24 len--; 25 } 26 strrev[i] = '\0'; 27 return strrev; 28} 29 30int main(void) 31{ 32 char *str; 33 char a[] = "Aiueo"; 34 str = a; 35 str = ft_strrev(str); 36 printf("%s\n", str); 37 return 0; 38}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

問題あります。 言語仕様の言葉で説明します。

オブジェクトは種類ごとの生存期間 (lifetime) を定める記憶域期間 (storage duration) を持ち、質問中のプログラムにある配列 tmp は自動記憶域期間 (automatic storage duration) に分類されます。

自動記憶域期間を持つオブジェクトはそれに関連付けられたブロックの終わりまでが寿命です。 tmp の場合は関数 ft_strrev の終わりが寿命であり、寿命を終えたオブジェクトにアクセスした場合の結果は未定義となります。

JISX3010:2003 (いわゆる C99 に相当) の 6.2.4 から引用します。

オブジェクトの生存期間 (lifetime) とは、オブジェクトに対して記憶域の確保が保証されている、プログラム実行の一部分をいう。 オブジェクトは、生存期間を通じて存在し、一定のアドレスをもち、最後に格納された値を保持する。 オブジェクトを生存期間の外部で参照したときの動作は未定義とする。 ポインタの値は、そのポインタが指すオブジェクトが生存期間の最後に到達すると、不定になる。

C における「未定義の動作」というのは「その状況を無視して予測不可能な結果を返しても良い」ということを意味し、元の値の残骸が残っていることもあればデタラメな値かもしれず、あるいはクラッシュしても仕様通りです。 要するに未定義とされていることは実質的にしてはいけないことであると考えて良いです。


tmp の宣言に static を付けて静的記憶域期間にすれば一応は未定義ではなくなりますが、一般的にはあまりよくはないスタイルです。 episteme さんが提示するように元の配列を書き換える方法か、あるいは書き込み先の配列も呼び出し側で用意して与える方法が普通は望ましいでしょう。

投稿2020/03/03 03:44

SaitoAtsushi

総合スコア5444

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kchan_01

2020/03/03 03:54

>>言語仕様の言葉 すごくわかりやすかったです。ありがとうございます。 >>要するに未定義とされていることは実質的にしてはいけないことであると考えて良いです。 未定義の捉え方が曖昧でしたが、理解できました。 >>episteme さんが提示するように元の配列を書き換える方法 この方法で書き換えようと思います。 ありがとうございました。
guest

0

問題アリです。

関数ft_strrevは、ローカル配列tmpの先頭アドレスを返しています。
tmpは関数内でしか有効でないので、外部で領域にアクセスした場合の挙動は未定義です。

また、str = ft_strrev(str) も本来許容されません。(註: 編集前の質問ではstrが配列型でした)

投稿2020/03/03 03:02

編集2020/03/03 03:09
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kchan_01

2020/03/03 03:15

str = ft_strrev(str)のコードの修正をしました。 ローカル配列tmpの先頭アドレスはアドレスであり、変数ではないため、問題ないかと思うのですが、何がいけないのでしょうか。
Kchan_01

2020/03/03 03:17

関数内で確保された領域は、関数を抜け出すと解放されてしまうということでしょうか。
LouiS0616

2020/03/03 03:24

先頭アドレスはただの値ですから、確かに返り値として用いることができます。 ただしそのアドレスに置かれたデータが生きているかどうかは別件です。
LouiS0616

2020/03/03 03:25

これは配列に限った話では無くて、例えば次のようなコードでも同じような問題が起き得ます。 int* func(void) { int a = 0; return &a; }
guest

0

※ 頓珍漢な回答なのは百も承知で
配列:char tmp[len] は要らなくね?

C

1#include <stdio.h> 2 3void ft_strrev(char *str) { 4 5 // p : 文字列の末尾('\0'の位置) 6 char* p = str; 7 while ( *p != '\0' ) ++p; 8 9 // strを増加/pを減少させつつ *str と *p を交換 10 for ( ; str != p && str != --p; ++str ) { 11 char tmp = *str; 12 *str = *p; 13 *p = tmp; 14 } 15} 16 17int main(void) { 18 char str[] = "Aiueo"; 19 ft_strrev(str); 20 printf("%s\n", str); 21 return 0; 22}

投稿2020/03/03 03:24

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kchan_01

2020/03/03 03:52

ありがとうございます。そちらの書き方で書かせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問