目次
1. printf の戻り値:
成功: 印刷された文字数を返します。
失敗: EOF が返されました。EOF はファイルの終わりで、マクロ定義は -1 です。
#include <stdio.h>
int main() {
char str[] = "123456789";
printf("%d\n", printf("%d\n", printf("%s\n", str)));
return 0;
}
最も内側の printf は「123456789\n」、合計 10 文字を出力し、戻り値は 10 で、2 番目の printf によって出力され、以下同様に続きます。
2.スキャンフ
Success: 成功した入力の数を返します。0 の場合もあります。
失敗: EOF が返されました。EOF はファイルの終わりで、マクロ定義は -1 です。
#include <stdio.h>
int main() {
int a = 0, b = 0;
printf("scanf返回值=%d\n", scanf("%d %d", &a, &b));
printf("a=%d\nb=%d", a, b);
return 0;
}
したがって、次のタイプのコードを書くことができます。
#include <stdio.h>
int main() {
int a;
char arr[10] = { 0 };
while (scanf("%d %s", &a, arr)==2){
printf("%d %s\n", a, arr);
}
return 0;
}
3. 戻り値のサイズ
sizeof の戻り値は size_t 型で、占有メモリのサイズを表す符号なし整数で単位はバイトです。
size_t は、一部の C/C++ 標準によって stddef.h で定義されます。size_t 型は、C のオブジェクトが達成できる最大長を表します。これは符号なし整数です。これはシステム間の移植の便宜のために定義されており、size_t はシステムごとに異なるように定義される場合があります。size_t は、32 ビット システムでは unsigned int、つまり 32 ビット符号なし整数として定義されます。64 ビット システムでは unsigned long、つまり 64 ビット符号なし整数として定義されます。size_t の目的は、システム内のメモリのアドレス指定可能な領域と一致するサイズを宣言する移植可能な方法を提供することです。
印刷には %zu を使用することをお勧めします。%u および %lu も使用できる場合があります。
#include <stdio.h>
int main() {
char a[] = "123456789";
char* p = a;
printf("%zu", sizeof(p));
return 0;
}
4. [ ] 添字参照演算子
#include <stdio.h>
int main() {
char a[] = "123456789";
printf("%c\n", a[5]);
printf("%c\n", 5[a]);
printf("%c\n", *(&a[0] + 5));
printf("%c\n", "123456789"[5]);
printf("%c\n", 5["123456789"]);
printf("%c\n", *("123456789"+5));
return 0;
}
一見すると、何だこれは奇妙なコードです。まず [ ] が何を意味するかを理解する必要があります。
文字列を定義するには 2 つの方法があります。
char* p="123456789"
文字 a[]="123456789"
文字列内の文字を出力する場合、どちらも文字列を定義できます。
*(p+i);
a[i]
2 つは同等なので、*(a+i)=a[i]
[ ] 演算子の定義は次のとおりです。
1. 配列を定義する場合、コンパイラに連続スペースを申請します。
2. ポインタ [ i ] は、ポインタの現在位置から開始して、ポインタが指す型のサイズの i スペースだけ後方にスキップすることを示します。
3.p[q] は *(p+q) と同等です。pq がポインタでない場合、エラーが報告されます。
3 番目の節に従って、コードを書くことができます。
5. { } と [ ] の置換
dev 5.11 などの一部のコンパイラでは、[ と ] の代わりに <: と :> を使用でき、{ と } の代わりに <% と %> を使用できます。
#include <stdio.h>
int main()
<%
char a<::>="abcdefghigk";
printf("%s",a);
return 0;
%>
6. 文字列の連結
""で囲まれた文字列をまとめると、自動的に文字列が結合されます。
#include <stdio.h>
int main() {
char* str = "aaaa""bbbb"\
"cccc";
printf("%s", str);
return 0;
}
7. 配列と配列名
配列と配列名を本当に理解していますか? 配列名は難しい場合があります。たとえば、配列 int arr[10] を定義した場合、arr が何を表すか知っていますか? これを読んだ後は、配列名についての知識を新たにすることができます。
1. 最初の要素のアドレスを表します。最初の要素の最初のバイトのアドレスを表すことに注意してください。
2. sizeof(arr) と &arr はアドレス全体のアドレスを表します (2 つの特殊な)
#include <stdio.h>
int main() {
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n", arr+1);
printf("%p\n", &arr);
printf("%p\n", &arr+1);
return 0;
}
arr と &arr を出力して、アドレスが同じであることを確認します。アドレスは同じですが、その意味は大きく異なることに注意してください。arr は最初の要素のアドレスで、arr+1 は 2 番目の要素のアドレスを表します。ステップサイズは4バイトで、これもint型のサイズです。&arr は配列全体のアドレスで、&arr+1 は配列全体のサイズである 40 のステップ サイズで配列全体にまたがることを意味します。
#include <stdio.h>
int main() {
int arr[10] = { 0 };
printf("%d\n",sizeof(arr));
return 0;
}
sizeof(arr) の戻り値は 40 バイトであり、この時点で arr が配列全体のアドレスであることがわかります。整数グループを表すアドレスはこれら 2 つの特殊なケースで構成され、残りのケースは受信要素のアドレスを表します。それだけだと思いますか?まだ終わっていないのです。
#include <stdio.h>
int main() {
int arr[10][10] = {0};
printf("%d\n",sizeof(arr));
printf("%d\n",sizeof(arr[0]));
printf("%d\n",sizeof(arr[0][0]));
return 0;
}
理解?arr は 2 次元配列です。arr は配列全体のサイズを表すため、400 バイトです。arr[0] は最初の行のサイズを表すため、40 バイトです。arr[0][0] はサイズです。最初の要素の値は 4 なので、引き続き見てみましょう。
#include <stdio.h>
int main() {
int arr[10][10] = {0};
printf("&arr: %u\n", &arr);
printf("&arr+1: %u\n", &arr+1);
printf("arr: %u\n", arr);
printf("arr+1: %u\n", arr+1);
printf("arr[0]: %u\n", arr[0]);
printf("arr[0]+1: %u\n", arr[0]+1);
printf("&arr[0]: %u\n", &arr[0]);
printf("&arr[0]+1: %u\n", &arr[0]+1);
printf("&arr[0][0]: %u\n", &arr[0][0]);
printf("&arr[0][0]+1:%u\n", &arr[0][0] + 1);
return 0;
}
&arr は配列全体のアドレスを表すため、&arr+1 のステップ サイズは 400、arr は最初の要素のアドレスを表します。配列は 2 次元配列であり、最初の要素は 10 int 型であることに注意してください。最初の行に数値があるため、ステップ サイズは 40 になります。arr[0] は arr の最初の要素の最初の要素 (a[0][0]) を表すため、ステップ サイズは 4 です。&arr[0] は arr[0] 全体を表すため、ステップ サイズは 40、&a[0][0] は最初の行と最初の列のアドレスを表し、ステップ サイズは 4 になります。&arr、arr、arr[0]、&a[0]、&a[0][0] は同じアドレスを出力しますが、それらの意味はまったく異なることがわかります。そうだと思いましたか?来て。
#include <stdio.h>
int main() {
int arr[3][4] = {
{1,22,333,444},
{5,66,777,8888},
{99,130,113,123}
};
printf("&arr:\t%u\n", &arr);
printf("&arr+1:\t%u\n", &arr+1);
printf("*arr:\t%u\n", *arr);
printf("*arr+1:\t%u\n", *arr+1);
printf("**arr:\t%u\n", **arr);
printf("**arr+1:\t%u\n", **arr+1);
printf("*arr[2]:\t%u\n", *arr[2]);
printf("*arr[2]:\t%u\n", *arr[2]+1);
return 0;
}
*arr は arr[0] 全体を表します。なぜですか? *arr=*(arr+0)=a[0]、つまり、ステップは行の要素サイズ、つまり 12 バイトであることを理解してください。 *arr= であるため、*arr は a[0][0] を表します。 [0] はすでにわかっています。それで
**arr=*arr[0]=*(arr[0]+0)=a[0][0]、 a[0][0] の値は 1 であるため、1 として出力され、続いて値を表す 1 1 を加算することは、アドレスの加算または減算ではありません。*arr[2] についても同様です。終わったと思いましたか?心配しないでください。他にもあります。
#include <stdio.h>
int main()
{
int i, j;
int arr[3][4] = { 1,22,3333,4,55,666,7,88,999,101,1167,12242 };
printf("*(arr+4*i+j)\n");
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++) {
printf("%d ",**(arr + 4 * i + j));
}
}
printf("\n");
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++) {
printf("%d ",**arr + 4 * i + j);
}
}
return 0;
}
**(arr + 4 * i + j)、arr は最初の要素を表し、ステップ サイズは要素の行の 12 バイトであるため、最初の 3 つが各行の最初の要素となり、後続のアドレスは範囲外になります。範囲はランダムな値です。**arr + 4 * i + j、**arr も arr[0][0] なので、毎回 1 を加算します。引き続き見てみましょう。
#include <stdio.h>
int main()
{
int i, j;
int arr[3][4] = { 1,22,3333,4,55,666,7,88,999,101,1167,12242 };
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++) {
printf("arr[%d][%d]=%d\t", i, j, *(&arr[0][0] + 4 * i + j));
}
printf("\n");
}
printf("\n");
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++) {
printf("arr[%d][%d]=%d\t", i, j, *(*(i + arr) + j));//i[a][j]
}
printf("\n");
}
return 0;
}
*(&arr[0][0] + 4 * i + j)、最初の行と最初の列の要素アドレス ステップ サイズを 1 として取得し、逆参照に 1 を追加して、配列のすべての値を出力します。*(*(i + arr) + j) は実際には a[i][j] ですが、どうやって調べましたか? a[i][i]=*(a[i]+j)=*(*(arr+i)+j) 、とても簡単ですね。ここでのみ、私は配列名の適用に精通しており、親しみやすさに注意を払っていると敢えて言えます。