【C言語初級】よく使う演算子を簡単に遊んでみる(2) - 代入演算子、単項演算子

ここに画像の説明を挿入

Junxi_ の個人ホームページ

勤勉であり、誰も待たないように何年も費やすことを奨励してください

C/C++ ゲーム開発


こんにちは、Jun Xi_ です。今日は演算子に関するコンテンツの第 2 部をお届けします。早速、直接始めましょう。

  • 正式な開始前に、オペレーターの基本的な内容を簡単に思い出すのに役立つマインド マップを今でも使用しています。

ここに画像の説明を挿入

  • 前に述べたことを続けてみましょう。

1. 代入演算子

代入演算子は、以前は満足できなかった値を取得できるようにする非常に便利な演算子です。つまり、自分自身を再割り当てできます

int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值。
  • 赋值操作符也可以连续赋值
int a = 10;
int x = 0;
int y = 20;
a = x = y+1;//连续赋值
//但是同样的语义我们也可以下面这样
x = y+1;
a = x;
//这样的写法是不是更加清晰爽朗而且易于调试。
  • したがって、通常は継続的な割り当てを特に推奨しません。

複合代入演算子

  • プラスは += に等しい
  • マイナスは -= に等しい
  • 乗算は *= に等しい
  • 等号で割る/=
  • 余りは ​​%= に等しい
  • 右シフトは >>= に等しい
  • 左シフトは <<= に等しい
  • ビット単位で &= に等しい
  • ビット単位か等しい |=
  • ビットごとの XOR は ^= に等しい
  • これらの演算子はすべて複合エフェクトとして作成できます。

比如:
int x = 10;
x = x+10;
x += 10;//复合赋值与上一行意思相同
//其他运算符一样的道理。这样写更加简洁

2. 単項演算子

1. 単項演算子の概要

論理逆演算!
負の値 -
正の値 +
アドレスおよび
オペランドの型の長さ (バイト単位) sizeof
バイナリの数値のビットごとの反転 ~
pre--、post-pre
-++、post-++
間接アクセス演算子 (逆参照演算子) *
強制型変換 (type)

  • 最初に簡単な例をいくつか挙げてから、途中でさらに重要な例をいくつか選んで説明しましょう。

#include <stdio.h>
int main()
{
    
    
	int a = -10;
	int* p = NULL;
	printf("%d\n", !2);
	printf("%d\n", !0);
	a = -a;
	p = &a;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof a);//这样写行不行?
	//printf("%d\n", sizeof int);//这样写行不行?
}
  • 結果を見てみましょう:
    ここに画像の説明を挿入

2. 論理逆演算子!

  • 上記の操作の結果に注目してください
printf("%d\n", !2);
printf("%d\n", !0);
  • これら 2 つの出力結果はそれぞれ「0」と「1」であることがわかります。
  • つまり!false (値 0) の場合は true (0 ではない)、! false でない場合は false (0)

3. オペランドの型の長さ sizeof を確認します。

  • sizeofの基本的な使い方はこんな感じです
sizof(所求类型)
  • ただし、上記の例の結果から次のことがわかります。
    printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof a);//这样写行不行?
  • 変数の場合、sizof のかっこは省略できますが、必要な長さが型の場合はかっこを追加する必要があります。

sizeof と配列

  • 一般に、sizeof は配列の要素の長さと数を見つけるために広く使用されています。
  • これを説明するための実際的な例を次に示します

二分法を使用して、順序付けされた配列内の特定の数値を見つけ、その数値の配列添字を出力します。

int main()
{
    
    
	int arr[] = {
    
     1,2,3,4,5,6,7,8,9,10 };//升序
	
	int k = 7;
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);//利用数组的总大小除以数组中一个元素的大小,得到数组中一共存放了几个元素
	//1
	int left = 0;
	int right = sz-1;//数组下标是数组元素个数-1
	int flag = 0;//flag的作用是标志是否找到了
	//2
	while (left<=right)//当左右都指向同一个数时还没找到,说明此数不存在
	{
    
    
		int mid = (left + right) / 2;
		if (arr[mid] == k)
		{
    
    
			printf("找到了,下标是:%d\n", mid);
			flag = 1;//令flag等于1
			break;
		}
		else if (arr[mid] < k)//mid就比k小,舍去比mid更小的数
		{
    
    
			left = mid + 1;
		}
		else//mid比k大,舍去比mid大的数
		{
    
    
			right = mid - 1;
		}
	}
	//1 2
	if (flag == 0)//判断是否找到k,如果找到,flag应等于1
		printf("没找到\n");

	return 0;
}
  • ここで注意してください:
int sz = sizeof(arr) / sizeof(arr[0]);//利用数组的总大小除以数组中一个元素的大小,得到数组中一共存放了几个元素
  • ここでは、sizeof を使用して配列要素の数を取得します。これは、次のステップで二分探索を実行するのに便利です

sizeof の使用中にいくつかのエラーが頻繁に発生します

  • ここでも、次のコンテンツを展開するためのコードを説明します。
#include <stdio.h>


void test1(int arr[])
{
    
    
	printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
    
    
	printf("%d\n", sizeof(ch));//(4)
}
int main()
{
    
    
	int arr[10] = {
    
     0 };
	char ch[10] = {
    
     0 };
	printf("%d\n", sizeof(arr));//(1)
	printf("%d\n", sizeof(ch));//(3)
	test1(arr);
	test2(ch);
	return 0;
}
/*问:
(1)、(2)两个地方分别输出多少?
(3)、(4)两个地方分别输出多少*/
  • 結果を見てみましょう:

ここに画像の説明を挿入

  • どうしたの?私たち 2 人は明らかに同じ配列のサイズを計算しましたが、結果が異なるのはなぜでしょうか?

  • ここでは配列とポインタについての知識を説明します。その理由を説明しましょう。

  • 1. 関数間のパラメータとして配列が渡される場合、実際に渡されるのは最初の要素のアドレスであるため、計算されるのは最初の要素のアドレスのサイズです。

  • 2. int 整数データの場合は 4 バイト、10 は 40 バイト、char 型データは 1 バイトしか占有せず、10 は 10 バイトを占有します。これが上記の答えの理由です。

  • この時点で、ここでの char 型が 4 バイトを占めるのはなぜですか? というちょっとした疑問が生じるかもしれません。char 型は 1 バイトしか占有しないと言いませんでしたか?

  • うーん…
    ここに画像の説明を挿入

  • もしそう思われた場合は、上記の説明をまだ理解していないことを意味しますので、ポインタ関連のコンテンツをもっと読むことをお勧めします。

  • ここで作成する受信フォームは 2 つの配列ですが、

void test1(int arr[])
void test2(char ch[])
  • しかし実際には、渡されるのは最初の要素のアドレスであり、実際にはポインタであると述べたので、次のように書くこともできます。
void test1(int *arr)
void test2(char *ch)

ここに画像の説明を挿入

  • 結果はまだ正しいです。
  • ポインタのサイズに関しては、同じオペレーティング システムでは、すべてのポインタ型のサイズは同じです。ここでは 32 ビット オペレーティング システムを使用し、ポインタ変数のサイズは一律 4 バイト、64 ビットでは一律 8 バイトです。

ここに画像の説明を挿入

  • さて、上記の結果の理由が理解できたと思います。

4. フロント++とフロント--

実際、この部分については特に話すことはありませんが、唯一注意する必要があるのは、使用するときに ++ または - - の操作を行ってから次のステップに進むことです。

  • 例えば:
//前置++和--
#include <stdio.h>
int main()
{
    
    
  int a = 10;
  int x = ++a;
  //先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
  int y = --a;
  //先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
  return 0;
  }

5. ポスト++とポスト--

pre-++ および pre-- とは対照的に、post-post ++ - - は、++ または - - 操作を実行する前に式が実行されるのを待ちます。

  • 例は次のとおりです。
//后置++和--
#include <stdio.h>
int main()
{
    
    
  int a = 10;
  int x = a++;
  //先对a先使用,再增加,这样x的值是10;之后a变成11;
  int y = a--;
  //先对a先使用,再自减,这样y的值是11;之后a变成10;
  return 0;
  }

前後の優先順位を証明する例を挙げてください

上で述べたことを証明するために、具体的な例を使用してみましょう。

#include <stdio.h>
int main()
{
    
    
	int a, b, c;
	a = 5;
	c = ++a;
	b = ++c, c++, ++a, a++;
	b += a++ + c;
	printf("a = %d b = %d c = %d\n:", a, b, c);
	return 0;
}
  • 上記コードの出力を判断するには
  • これは秘密ではなく、答えは直接発表されます。
    ここに画像の説明を挿入
  • 思った通りの結果でしょうか?
  • 分解してみましょう

int main()
{
    
    
	int a, b, c;
	a = 5;
	c = ++a;//前置++ c=6
	b = ++c, c++, ++a, a++;//逗号表达式整个表达式的结果是最后一个表达式的结果,这里先记住这个结论,具体解释我们后面再说
	//此时b=a++,由于后置这里就是a,但是前面执行了++a,此时a的值为7所有b就等于7
	//执行完b表达式后,开始执行后置的++,此时c等于8,a也等于8
	b += a++ + c;//这句话写清楚点就是b=b+a++ +c,此时b=7+8+8=23
	//最后再执行一次a后置++,a的值变为9
	printf("a = %d b = %d c = %d\n:", a, b, c);
	return 0;
}
  • このように分析すると、出力結果は画面に印刷した結果と一致しますか? この例を読んで、pre-post++(- -)についての理解は深まりましたか?

6. ~ 2 の補数のビットを反転します

//~ 按补码二进制位取反

int main()
{
    
    
	int a = 0;
	printf("%d\n", ~a);//?
	//00000000000000000000000000000000 -a的补码
	//11111111111111111111111111111111 - ~取反后的补码
	//11111111111111111111111111111110
	//10000000000000000000000000000001 -1//打印时打印的是该数的原码
	return 0;
}

ここに画像の説明を挿入


7. アドレス演算子 & と逆参照演算子 * を取得します。

  • これら 2 つのほとんどはポインタで使用されます。実際には、話すことが何もないので詳しくは説明しません。ポインタに関する関連ブログは後ほど投稿します。

8. 必須の型変換 ()

  • あるライブラリ関数や他の関数を参照する際、入力データ型がその関数で定義されているデータ型と一致しない場合があり、このとき入力データを強制的に必要なデータ型に変換する必要がありますが、諺の通り、難しい型変換は甘くなく、強制的な型変換を行うとバグが発生する場合があります。

  • 例えば:

int main()
{
    
    
	int a = (int)3.14;//强制
	printf("%d\n", a);
	
	return 0;
}

ここに画像の説明を挿入

  • float を int にキャストします。
  • しかし、このコードの欠陥も明らかです。小数点以下のデータが失われます。つまり、強制的な型変換のプロセスでデータ損失が発生しやすいのです。
  • 機能中のアプリケーション
  • スリームーンチェスの乱数の直接生成でそのようなコードを確認しました。
srand((unsigned int)time(NULL));//把时间函数置空传给srand同时由于srand要求参数必须为unsigned int型,把time(NULL)强制类型转换一下

要約する

  • 今日の内容はこれで終わりです。今日は代入演算子と単項演算子の具体的な使用法について話しました。まだ混乱している場合は、自分でやってみると良いでしょう。この分野の知識は少し抽象的であり、慣れるには繰り返し練習する必要があります。
  • 以上がオペレーター編の後編ですが、他のオペレーターアプリの詳しい解説も近々まとめて更新していきますので、お楽しみに!
  • 質問がございましたら、コメント欄またはプライベート メッセージでお問い合わせください。また次回お会いしましょう。

新しいブロガーを作成するのは簡単ではありません。記事の内容が役立つと思われる場合は、離れる前にこの新しいブロガーをクリックするとよいでしょう。皆様の応援が更新の励みになります!

**(Ke Li はブロガーを 3 回連続でサポートするようお願いしています!!! 以下のコメントをクリックして「いいね」を押し、Ke Li を支援するために集めてください)**

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/syf666250/article/details/131378155