1.文字列リテラル。
「キャンディーは\ nダンディです\ nしかしリキュールは\ n速いです。」
これは、C ++では文字列リテラルと呼ばれます。「\ n」などの転送シーケンスを文字列内に埋め込むことができます。
文字列に8進数と16進数の転送シーケンスを埋め込むように注意してください。8進数の転送シーケンスは/で始まり、16進数の転送シーケンスは/ xで始まり(xは小文字である必要があります)、8進数の転送シーケンスは3桁です( 0〜7の範囲)後で終了するか、最初の8進数以外の数値で終了します(数値は8以上で終了します)。
16進数の/ xの後に制限はなく、最初の非16進数(fより大きい)で終わります。16進数は大文字にできることに注意してください(コンパイラーの結果から取得)。たとえば、次のコードを見てください。
#include <stdio.h>
int main()
{
if(('\xAA') == ('\xaa'))
printf("equal");
else
printf("not equal.");
return 0;
}
操作の結果は次のとおりです。
equal
2.文字列リテラルを続行します。
(1)方法1:\を使用する
たとえば、「私は学生です\
そしてあなたは教師です。「」
特徴:最初の行は\(含まれていません)で終わり、2番目の行は行の先頭から始まります。
(2)方法2:2つ以上の文字列が隣接している場合、C言語は自動的に文字列をマージします。このルールを使用して、このように記述します
"私は学生です "
「そしてあなたは先生です。」
最後に、コンパイラは文字列自体をマージします。「私は学生で、あなたは教師です。」
3.文字列リテラルの保存。C言語は、文字列リテラルを文字配列として格納します。c言語が長さnの文字列を検出すると、文字列リテラルに長さn + 1のメモリ空間を割り当て、末尾に「\ 0」を追加します。注:ここで「\ 0」、「0」、および「」を混同しないでください。ヌル文字のコード値は0、「0」(ASCII)のコード値は48、スペースのコード値は'' ASCllは32です。覚えておいて、文字配列がデフォルトで初期化されている場合、それは「\ 0」になります。
文字配列がデフォルトで初期化されると、各文字にもスペースバーの代わりに「\ 0」の値が割り当てられ、算術型配列の各桁は0に初期化されます。
空の文字列は ""で、空の文字列は単一の空の文字 '\ 0'として格納されます。
文字列は文字通り配列として格納されるため、文字列は文字通りポインタとして扱われます(配列名はポインタとして扱われます)。たとえば、printf( "abcde");の場合、文字列 "abcde"が渡されます。 printf関数へアドレス(つまり、文字aのメモリユニットへのポインタ)。
4.文字列リテラルはポインタとして扱われます。
例:「abc」
printf( "abc");ここで、 "abc"は、文字aのメモリユニットへのポインタと見なされます。
printfとscanfはどちらも、最初のパラメーターとしてchar * typeを受け入れます。
5.文字列リテラルの操作。
(1)文字列リテラル値は変更できません。次のコードを見てください。
#include <stdio.h>
int main()
{
char *str = "abcde";
*str = 'a';
printf("%s",str);
return 0;
}
実行結果でランタイムエラーが発生しました:
r@r:~/coml_/c/13/2$ gcc 3.c -o 123
r@r:~/coml_/c/13/2$ ./123
Segmentation fault (core dumped)
r@r:~/coml_/c/13/2$
結論:文字列リテラルの内容は変更できません。ただし、char *オブジェクトが別の文字列を指すようにすることはできます。
#include <stdio.h>
int main()
{
char *str = "abcde";
printf("%s\n",str);
//str 重新指向另一个字符串字面量
str = "efghikasdfasd fasdf asdf asdf asf";
printf("%s",str);
return 0;
結果は次のとおりです。
abcde
efghikasdfasd fasdf asdf asdf asfr
予期しない場所:元の文字列の長さを超える可能性があります。
(2)半分の場合、char *が必要な場所ならどこでも文字列リテラルを使用できます。
たとえば、char * p;
p = "abc";この操作は、文字列をコピーするのではなく、文字aのアドレスをpに割り当てることです。つまり、文字列の割り当てプロセス全体ではなく、ポインタ変数pの割り当てプロセスです。
(3)ポインタには添え字演算があり、文字列リテラルにも
「abc」[1]は文字bを指します
次の関数は、整数を16進文字に変換します。
char number_to_hex(int n)
{
return "0123456789ABCDEF"
}
(4)ここで、16進数と8進数、および転送シーケンスは同じではないことに注意してください
(a)16進数の定義\ x00(xは大文字と小文字の両方、数値部分には長さの要件はありません)、8進数の定義\ 012(数値0の先頭は8進数、および数値\ 0の後の長さの制限はありません)
(b)16進エスケープシーケンスは\ xで始まる必要があり(xは小文字で、次の桁は0からffまで最大2桁である必要があります)、8進転送シーケンスは\で始まり、次の桁はで最も3桁の数字。次の図を参照してください。レビューを
6.文字列リテラルと文字定数は交換できません。次のコードを参照してください。
#include <stdio.h>
int main()
{
printf("\n");
printf('\n'); //这里引发错误
return 0;
}
gccコンパイラのコンパイル結果は次のとおりです。
r@r:~/coml_/c/13/2$ gcc 4.c -o 123
4.c: In function ‘main’:
4.c:5:8: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [-Wint-conversion]
5 | printf('\n');
| ^~~~
| |
| int
In file included from 4.c:1:
/usr/include/stdio.h:332:43: note: expected ‘const char * restrict’ but argument is of type ‘int’
332 | extern int printf (const char *__restrict __format, ...);
| ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
4.c:5:1: warning: format not a string literal and no format arguments [-Wformat-security]
5 | printf('\n');
7.文字列変数。「\ 0」で終了する必要があることに注意してください。そうでない場合、ライブラリ関数が呼び出すときに未定義の動作が発生します。
#include <stdio.h>
#define STR_LEN 20
int main()
{
//方法1:直接定义成字符数组+初始化
char str[STR_LEN + 1] = "you are welcome.";
//方法2:直接定义为char * + 初始化
char * str1 = "you are welcome.";
//方法3:先定义一个字符数组,和一个char *,把char *对象指向一个char 数组
char str2[STR_LEN + 1],*str3;
str3 = str2;
//方法4:先定义一个char *,后来可以指向一个字符串字面值
char *ptr;
ptr = "you are welcome";
puts(ptr);
return 0;
}
ただし、scanfを使用してchar *を読み取る場合は、最初に十分なスペースを開く必要があります。つまり、最初に型をchar [STR_LEN + 1]として宣言する必要がありますが、型char *としては宣言しないでください。
char * p; //ポインタpがポインタスペースを格納するのに十分なだけです。文字列にスペースを割り当てることはできません。pを使用して読み込むと、エラーが発生します。
#include <stdio.h>
int main()
{
char *p;
scanf("%s",p);
printf("%s",p);
return 0;
}
操作の結果は次のとおりです。必要に応じてaresdfを入力した後、出力は実際にnullになります。
you arasdf
(null)
8.文字列変数を初期化します
c言語が配列初期化式を処理する場合、配列初期化式が配列自体によって短縮されると、残りの配列要素は0に初期化され(要素はint、float、double)、char配列は同じ規則に従います。 。 '\ 0'が追加されました。
char *またはchar [](値のタイプは文字列リテラル)に値を割り当てても、末尾に「\ 0」が自動的に追加されます。
#include <stdio.h>
int main()
{
double d[12] = {0.0};
int i;
for(i = 0; i!= 12; ++i)
{
printf("%f\n",d[i]);
}
return 0;
}
~
結果は次のとおりです。
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
9.文字配列と文字ポインタ
類似点:文字配列または文字ポインターが受け入れられる場合は常に、両方を実際のパラメーターとして使用できます。
差:
(1)文字配列は文字の値を変更できますが、文字ポインタは文字列リテラル値を変更できません。
(2)文字配列の名前は配列名であり、文字ポインタは変数であり、実行中に他の文字列を指すことができます。
たとえば、char * pです。ここで、pはcharオブジェクトを指すポインタ変数です。pの値は変更できます(pが指すオブジェクトは変更できません。* p = ...(違法)とp = ...(合法)を区別してください)
char * p;
p = "abcde"; //リーガル、変更されたpの値は次のとおりです。pは変数ですが、もちろん変更することもできます。
* p = "efghi"; //不正です。pが指す文字列リテラルを変更する場合は、エラーが報告されます。
10.文字列の読み取りと書き込み
(1)読む
scanfまたはfget();を使用します。
機能:最初以降のすべての空白は無視されます。たとえば、bc defを入力すると、最初の空白は無視され、最後にaが読み取られ、後者の一部がメモリにキャッシュされて待機します。後続の読み取り用。
(2)書く
printf( "")は、最初の「\ 0」に遭遇するまで、厳密に1つずつ出力します。文字列の最後に「\ 0」がない場合は、最初の「\ 0」まで書き続けます。メモリが検出されました。0 '。
puts()は、行の最後に直接「\ n」を追加します(自動折り返し)
(3)文字列読み取り関数を記述して解決すべき問題は次のとおりです。
(a)いつ読み取りを開始するか(最初の空白文字を無視するかどうか)(b)「\ n」を終了する方法、スペースはまだ特定の文字であり、終了文字を文字列に書き込む必要があるかどうか(c)読み取り文字列が長すぎる場合、余分な文字は直接無視されるか、次の入力操作のために残されます。
たとえば、改行文字が無視されない場合、最初の改行文字は終了し、改行文字は文字列に存在しません。次に、次のように記述します。関数read()をコードに記述します。
#include <stdio.h>
#define LEN 20
int read(char str[],int n);
void print(char str[],int n);
int main()
{
char array[LEN + 1] = {' '};
read(array,LEN);
print(array,LEN+1);
return 0;
}
int read(char str[],int n)
{
char ch;
char *p = str;
int i = 0;
while((ch = getchar()) != '\n')
{
if(i < n)
{ *p ++ = ch;
i++;
}
}
*p = '\0';
return i;
}
void print(char str[],int n)
{
int i = 0;
for(i = 0; i!= n; ++i)
{
printf("%c",str[i]);
}
}
関数read()は、次のように簡単に記述することもできます。
int read(char str[],int n)
{int i = 0;
char ch;
while((ch = getchar()) != '\n')
{
if(i < n)
str[i ++] = ch;
}
str[i] = '\0'; //terminates string
return i; //number of characters stored
}
scanf関数とgets関数は、最後に自動的にヌル文字を追加します。ただし、関数を自分で作成する場合は、自分でヌル文字を追加する必要があります。