(C言語)文字配列と文字列の違い。
フォーマット演算子等についての違いが知りたい方は、以下の記事で書いてますので是非参考にしてみてください。
始めに
上の記事で int array [ ] ≒int* arrayと説明し、 ニアリーイコールがついていますがこのことについて話します。
どちらともぱっと見キャストとして使うことが可能ですが、内部の構造が若干違います。
実は
- char array[ ]="abcde"<=>char array[ ]={"a","b","c","d","e"}となっています。
- char* array<=>const char* arrayはそのままです。
この大きな差は
- 領域なのか値なのかです。
- スコープ(範囲)が異なる
ここで問題になるのが値が代入できない点です。
詳しく見ていきましょう
代入できない
char a[ ]="abcde"; char* b="ABCDE"; b=a; printf("%s\n",b);
結果
abcde
これはできる。じゃあ逆は??
char a[ ]="abcde"; char* b="ABCDE"; a=b; //ここが違う printf("%s\n",b);
結果
error: assignment to expression with array type 8 | a = b; | ^
出来ない。。
このように代入できないときが発生します。
これはaは[ ]で定義しており、[ ] は領域を指し、アドレスを格納するメモリが存在しないからです。
補足
a[0]=v等のことならできます。
スコープが異なる
パターン1
char* aa(){ char* array="abcde";//ここが* return array; } void main(){ puts(aa()); }
結果
abcde
パターン2
char* aa(){ char array[ ]="abcde";//ここが[ ] return array; } void main(){ puts(aa()); }
結果
warning: function returns address of local variable [-Wreturn-local-addr] 6 | return array; | ^~~~~
エラーが出てしまいました。
このエラーは返り値でローカル変数返すなよ。。と言っていてスコープが狭いことを意味します。
こういったところで注意が必要になります。
まとめ
- [ ]で作った文字配列はアドレスの変更ができない。(1つ1つの変更なら可能)
- [ ]で作った文字配列はスコープが自分自身のみ
参考
(C言語)2重ポインタについて
2重ポインタについて少しですがわかりやすくまとめて置きます。
そもそもポインタとは、
変数を定義したときに変数はアドレスというものを持っていて、その別名として変数名があるような形になっています。 このアドレスをつかさどるのがポインタです。
ポインタを使うことで変数をアドレスとして使うことができます。
ここで変数名で使えばいいやんと思うかもしれないが、c言語には文字列という概念が備わっていないので、アドレスを活用して文字列を使います。
1重のポインタ
書き方
int a=10; int\* p; //int \*pでも大丈夫 p=&a; //&は後ろの変数のアドレスを読み取るものです。 printf("%d\n",\*p);// \*はアドレス値から値を読み取ります。
詳しく日本語で説明
- 整数aの値を10とする。(10は値であってアドレスではないです。)
- 整数ポインタ変数pを宣言する。(ポインタ変数にもcharの型etc..があります。)
- 整数ポインタ変数pにaのアドレス値を代入します。
- 整数ポインタ変数pに入っている数値(アドレス)の値を出力します。
これは1重のポインタです。
- *(宣言時)・・・ポインタ変数ですよって意味
- &・・・変数からアドレスと読み取る
- * ・・・アドレスから変数(の値)を読み取る
(アドレス値は適当です。)
&と*は対義語みたいなものです。
2重ポインタ
書き方
int a=10; int\* p; int\* pp; p=&a; //&は後ろの変数のアドレスを読み取るものです。 pp=&p printf("%d\n",\*\*pp);// \*はアドレス値から値を読み取ります。
詳しく日本語で説明
- 整数aの値を10とする。
- 整数ポインタ変数pを宣言する。
- 整数ポインタ変数ppを宣言する。<-違うところ
- 整数ポインタ変数pにaのアドレス値を代入します。
- 整数ポインタ変数ppにpのアドレス値を代入します。
- 整数ポインタ変数ppに入っている数値(アドレス)の値を出力します。
(アドレス値は適当です。)
最後なんて**となっていて*が2つもあります。
この*の数で何重ポインタと言っているのです。
↓↓こんな感じです。。↓↓
まとめ
- *と&は対義語
- わからなくなったら一つ一つ置換(代入するとわかりやすい)
(C言語) 配列宣言の仕方([] *)
C言語の配列
c言語の配列で1年弱でようやく理解したのでまとめました。
- 配列のキャストについて
- printf時のフォーマット指定子
配列のキャスト
軽いまとめ
int array≒int* array
char array≒char* array
[] , *をすることでキャストを宣言します。
補足
キャストとは...
なんでも入ってよい箱(配列,変数)ではなく、専用の箱を作るイメージ
この箱には整数のみ、この箱には小数のみetc...
なぜ≒なのかは下の記事について詳しく書きます。
じゃあなかったらどうなるの??
char array="abcd";で宣言をする
void main(){ //#include <stdio.h>をしています char array="abcd"; printf("%s",array); }
結果
test.c: In function ‘main’: test.c:6:16: warning: initialization of ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversio ] 3 | char array = "abcd"; | ^~~~~~
これはキャストされていないことを意味し、おいおい1文字しか受け付けないところに2文字以上入れるなよ的な感じです。
ここでchar array[]またはchar* array にすることでキャストされうまく実行いたします。
void main(){ char array1[]="abcd"; //[]でキャスト char* array2="abcd"; //*でキャスト printf("%s",array1); printf("%s",array2); }
結果
abcd abcd
printfの%d,%c,%sの違い
%d,%cはそれぞれ一文字の数字と文字対応 %sは文字列に対応
簡単じゃんと思うかもしれないが、変数の指定の仕方に注意。。。
char* array="abcd"; printf("%c\n",*array);//*あり printf("%s\n",array);//*なし
結果
a abcd
array=array[0]を意味します。 もし2番目のbを取り出したければ(array+1) or array[1]することでうまくいきます。
char* array="abcd"; printf("%c\n",*(array+1));//*あり printf("%c\n",array[1]);//*なし
結果
b b
このように配列名は先頭のポインタを指しますがその際*を付けるのか付かないのかで意味が大きく変わってくるので注意が必要です。
まとめ
- 配列を宣言する時は[]または*をつける
- 文字列を表示する時は*なし。1文字のみの時は*あり。
(Rails) deviselogin出来ないときの対処法(devise)
状況
sign upはできるがloginができない。
(Sign upはname,email,passwordで登録し、Log in時はname,passwordで認証する。)
原因
ストロングパラメーターは設定していたが、/config/initializers/devise.rbのほうを変えていなかった
apprication_controller
before_action :configure_permitted_parameters, if: :devise_controller? private def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name])#変更前 devise_parameter_sanitizer.permit(:sign_up, keys: [:email])#変更後 end
devise.rb
config.authentication_keys = [:email]#変更前 config.authentication_keys = [:name]#変更後
詳細
emailとnameの指定が逆だった。
意味としては、apprication_controllerでsign up時にemail登録を許可し、devise.rbでuser認証時のチェックをnameで行いますよ
ここで実験
- devise.rb->email,apprication_controller->nameの場合
- devise.rb->email,apprication_controller->emailの場合
- devise.rb->name,apprication_controller->nameの場合
- devise.rb->name,apprication_controller->emailの場合
error
- 成功
- 登録時::name can't be blank,ログイン時::Unpermitted parameter: :name
- 登録時::Email can't be blank
- ログイン時::Unpermitted parameter: :name
実験からの考察
user認証をするときに値を取得するのはdevise.rbのほうで行い、 登録する時はdevise.rb,apprication_controller両方を用いる。
まとめ
email以外で認証する時は、devise.rbも変えよう!
(Rails) @book.user_idと@book.userの違い
model
book | user |
---|---|
id | id |
book | name |
user_id |
注意::userとbookには1:Nの関係がある。
状況
この時、bookからuserを指定する時に2通りの書き方ができるように思える。
@book.user_idと@book.userである。(@bookにはidが1つの入る)
しかし、これらは異なるものである↓↓
@book.user_id・・・user_id
@book.user・・・Userのレコード
詳細
@book.user_id #@bookでレコードを指定し、そのレコードのカラムであるuser_idを指定する。 @book.user #@bookでレコードを指定し、そのuser_id=user.idのuserのレコードをしてする。
@book.user_id @bookでレコードを指定(水色)し、.user_idでuser_idを指定(赤色)する。 @book.user @bookでレコードを指定(水色)し、.userでuser_idと同じuserの中のidを指定(赤色)する。そしてそのレコードを指定(黄色)する
上が@book.user_idで下が@book.userである
おまけ
modelに関数を書いた際は、@book.userの方でUserのレコードを指定しないと使えないことに注意。
まとめ
@book.user_id・・・user_id
@book.user・・・Userのレコード
def display_name(user_id) user_id.name end
(Rails) form_with modelではなくform_with urlを使いこなす
状況
投稿機能を作った際にcontrollerの中でindexとcreateの2つの部分でmodel名.newが使われていた。
また、全てのviewのアクションに対して、model名.newを用意するのが面倒である(before_action等を使えば防げるが...)
これは「rbの基本として、重複は避けるとある。」に反すると思い、回避できるのかを試してみた。
補足
indexのmodel名.newは「この箱に入れてください」という仮の箱を用意し、
createのmodel名.newは「仮の箱から取り出して正式な箱に入れてください」という感じ
結論
<%=form_with model:%>と<%=form_with url:%>を使い分けることで実現する。推奨ではない。
詳細
<%=form_with model:%>と<%=form_with url:%>の差
イメージとしてはもともとmodelの型(値を入れる箱)を作るか作らないかの差
そもそも <%=form_with model:%>と<%=form_with url:%>の違いはdbに保存するかどうかである。 簡単に言うとdbに保存する時に分かりやすくするかの違いである。
また、違いを別の言い方をすると、情報を送った時に2重のハッシュにするかどうかである。
投稿フォーム
view
# ココに<%=form_with ...%>が入る #model or url <%=f.text_field :name%> <%=f.submit "send"%>
<%=form_with model:%>の場合
出力結果
Parameters: {"authenticity_token"=>"[FILTERED]", "newname"=>{"name"=>"model"}, "commit"=>"send"} # 2つめの"newname"=>{"name"=>"model"}に注目
<%=form_with url:%>の場合
出力結果
Parameters: {"authenticity_token"=>"[FILTERED]", "name"=>"url", "commit"=>"send"} # 2つめの"name"=>"url" に注目
nameの部分が違うことがわかる
この時、<%=form_with url:%>の方はコントローラーのcreate以外でnewを呼び出す必要がない。➡重複しない
この際、アクションのcreateで用いるparams部分で注意が必要であり、
<%=form_with model:%>の場合
params.require(:newname)permit(:name)
<%=form_with url:%>の場合
params.permit(:name)
となる。 これはrequire部分で、2つ目のハッシュを指定するためである。
まとめ
controller内のmodel.newの重複を防ぐことを試していた。
<%=form_with url:%>を用いることで重複を防ぎいちいちmodel名.newを作成するのを防いだ。
この時、paramsに気を付けないとエラーとなる。
(Rails)全てのviewで使えるインスタンス変数の作成
状況
application_controllerにてインスタンス変数を定義したがうまく引き継がれない
controller
class ApplicationController < ActionController::Base @variable='10' end
原因
コールバック(before_action)をしていなかったため。
実施したこと
メソッドの中に変数を定義した。
よって以下のようになる
controller
class ApplicationController < ActionController::Base before_action :setting private def setting @variable='10' end end
このようにすることで無事格納される。
まとめ
変数を定義する際はメソッドの中に書くのする必要がある。