文字列の定義と基本的な使い方
1. 文字列とは
ダブルクォートで囲まれた文字のコレクション! 例: "hello"、"world"、または'\0'で終わる文字配列! !!
例: char ch[] = {'h', 'e', '\0'}
注: "hello" には実際には最後に '\0' がありますが、それが表示されます。
つまり、文字列は'\0' で終わる必要があります。!
「hello」に文字「\0」が含まれていることを確認するにはどうすればよいですか?
printf("%d\n", *(p+5)); 出力結果が整数 0 の場合は、末尾が '\0' であることを意味します
2. 文字列と文字配列の関係と違い
文字列は文字配列として扱うことができますが、文字配列は必ずしも文字列として扱われるとは限りません。
文字配列には必ずしも「\0」が存在するとは限らないためです。
char ch[] = {‘a’, 'b', '\0', 'c', 'd'};
この場合、配列 ch を文字列 "ab" として扱うことができますが、
実際の作業では、複数の文字を格納するために文字配列を使用する必要があり、これらの複数の文字を文字列として扱う必要があることがよくあります。ただし、文字配列を定義するときにわかるのは、保存する必要がある最大文字数 (30 文字と想定) だけであり、実際の保存中に保存される文字は 30 文字未満になる可能性があります。文字列として?
c har name[ 30 ] ;
memset(name, 0, sizeof(name));
注: 文字配列の長さを定義する場合、通常は、実際に格納されるバイト数 + 1 より大きくなります(最後のバイトは「 \0 」として保存する必要があるため)。
3. 文字列操作
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
//字符串的操作:
char *str;
char ch[] = {"hello"};
str = ch;
//可以通过指针str操作ch
//方法1:
str[1] = 'a'; //当一个指针指向了一个数组以后,我们就可以通过指针使用下标法直接访问数组中的元素
//方法2:
*(str + 1) = 'a';
//也可以将字符串常量赋值给一个指针变量
char *p = "hello";
/*注意:p是一个指针变量,应该保存的是一个地址,因此 char *p = "hello"; 并不是将字符串"hello"赋值给
指针变量p,而是将存储字符串 "hello"的内存空间的首地址赋值给p
*/
return 0;
}
4. 文字配列の各要素を「\0」に割り当てます。
#include <string.h>
void *memset(void *s, int c, size_t n);
memset関数:ポインタ s が指すメモリ空間の n バイトを C
サンプル コードに埋め込みます。
#include <stdio.h>
#include <string.h>
int main()
{
char ch[10];
memset(ch, 0, sizeof(ch)); //memset(ch, 0, sizeof(ch));
printf("view the data ch: %d\n", ch[0]);
return 0;
}
5. 次のコードのどこが間違っているのか分析してください。
char *p = "hello";
p[0] = 'A';
2 つの一般的な文字列処理関数
1.アトイ関数
#include <stdlib.h>
int atoi(const char *nptr);
機能:文字列をint 型の整数に変換し、変換された整数値を返します。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char *p = "1234";
int val = atoi(p);
printf("view the data: %d\n", val);
return 0;
}
演習: atoi 関数を実装するコードを作成します。
2. atof関数
#include <stdlib.h>
double atof(const char *nptr)
機能:文字列を double 型の浮動小数点数に変換し、変換された浮動小数点数を返します。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *p = "123.456";
double val = atof(p);
printf("%f\n", val);
return 0;
}
3. strlen関数
#include <string.h>
size_t strlen(const char *s);
機能:文字列の長さを計算します。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *ch = "hello";
char arr[] = {'A', 'B', 'C', '\0', 'D'};
printf("%d %d\n", strlen(ch), strlen(arr));
return 0;
}
考えてみます: strlen(arr) の結果が 3 になるのはなぜですか?
演習: strlen 関数を実装するためのプログラミング
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char *ch = "hello";
char arr[] = {'A', 'B', 'C', '\0', 'D'};
printf("%d %d\n", strlen(ch), strlen(arr));
return 0;
}
考えてみます: strlen(arr) の結果が 3 になるのはなぜですか? 演習: strlen 関数
を実装するためのプログラミング
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int my_strlen(char ch[]) //int my_strlen(char *ch)
{
int cnt = 0;
int i = 0;
while (ch[i] != '\0')
{
cnt++;
i++;
}
return cnt;
}
4. strcpy関数
#include <string.h>
char *strcpy(char *dest, const char *src);
機能: src の指す文字列を dest の指す空間にコピー、過去に'\0'もコピー
パラメータ:
dest :コピー先文字列の先頭アドレス
src :コピー元文字列の先頭アドレス
戻り値:
成功: 返却先文字列 失敗した先頭アドレス
: NULL
サンプルコード:
#include <stdio.h>
#include <string.h>
int main(){
char *src = "hello";
char dst[10] = {0};
strcpy(dst, src);
printf("src: %s, dst: %s\n", src, dst);
return 0;
}
注:
1. dst のスペースは、src からコピーされるコンテンツが占めるスペースよりも少なくとも 1 バイト大きくなければなりません('\0' のスペースが予約されているため)。
#include <stdio.h>
#include <string.h>
int main(){
char a[4];
char b[4]; //hello
strcpy(b, "hello");
printf("view the data b: %s\n", b); //hello
printf("view the data a: %s\n", a); //0
return 0;
}
2. strcpyの実装
char *strcpy(char *dest, const char *src, size_t n){
size_t i;
for (i=0;i<n && src[i] != '\0'; i++)
dest[i] = src[i];
for (; i<n; i++)
dest[i] = '\0';
return dest;
}
5. strncpy関数
#include <string.h>
char *strncpy(char *dest, const char *src, size_t n);
機能: src が指す文字列の最初の n 文字を dest が指すスペースにコピーします。ターミネータをコピーして、指定された長さに '\0' が含まれるかどうかを確認します。
パラメータ:
dest: 宛先文字列の最初のアドレス
src: ソース文字の最初のアドレス
n: コピーする文字列の数を指定
戻り値:
成功: 宛先文字列の最初のアドレスを返す
失敗: NULL
注:
1. strncpy は n バイトまでコピーできます。最初の n バイトに '\0' がなければ、最後まで '\0' はコピーされません。
2. src の長さが n 未満の場合、合計 n バイトが書き込まれることを保証するために、一部の '\' は 0' に書き込まれます。コピー時に strncpy が前の n バイトにすでに '\0' を持っている場合は、'\0' にコピーされるだけですが、それでもコピーされます。宛先 '\0' への書き込みを続けて、合計 n バイトが書き込まれるようにします。
strncpyの実装:
char *strncpy(char *dest, const char *src, size_t n){
size_t i;
for (i=0; i<n && src[i] != '\0'; i++)
dest[i] = src[i];
for (; i<n; i++)
dest[i] = '\0';
return dest;
}
6. strcpyとstrncpyの違い
dest の領域が src の領域よりも大きいことが100% 確信できる場合は、 strcpy を使用できますが、実際の作業では、
オーバーフローを避けるために、できる限りstrncpy を使用するようにしています。
ここでまた問題が発生します!strncpy を使用するときに、n が dest が指すメモリ空間のサイズより大きい場合でも、オーバーフローが発生しませんか? では、このオーバーフロー状況を回避するにはどうすればよいでしょうか?
方法: まずdest の長さ len と n のサイズを判断し、 len>=n の場合は n 個の要素をコピーし、 len<n の場合は len 個の要素をコピーします。
7. strcat関数
#include <string.h>
char *strcat(char *dest, const char *src);
関数: src 文字列を dest の最後に接続すると、'\0' も追加されます
パラメータ:
dest: 宛先文字列の最初のアドレス
src: ソース文字の最初のアドレス
戻り値:
success: 最初の文字列を返します宛先文字列のアドレス
失敗: NULL
サンプルコード:
#include <stdio.h>
#include <string.h>
int main(){
char ch[20];
memset(ch, 0, sizeof(ch));
strcpy(ch, "hello");
strcat(ch, "world");
printf("view the data: %s\n", ch);
return 0;
}
注: ch のスペースは十分に大きい必要があります。
strcat の実装:
#include <stdio.h>
#include <string.h>
char *strncat(char *dest, const char *src, size_t n){
size_t dest_len = strlen(dest);
size_t i;
for (i=0; i<n && src[i] != '\0'; i++)
dest[dest_len + i] = src[i];
dest[dest_len + i] = '\0';
return dest;
}
8. strncat関数
#include <string.h>
char *strcat(char *dest, const char *src);
関数: src 文字列を dest の最後に接続すると、'\0' も追加されます
パラメータ:
dest: 宛先文字列の最初のアドレス
src: ソース文字の最初のアドレス
戻り値:
success: 最初の文字列を返します宛先文字列のアドレス
失敗: NULL
注意:
- src のコンテンツの長さが n バイト未満の m の場合、m+1 バイトのみが追加されます (最後に「\0」が自動的に追加されます)。
- src のコンテンツの長さが n バイト未満の m の場合、n+1 バイトを追加します (最後に「\0」が自動的に追加されます)。
サンプルコード:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char *p;
p = (char *)malloc(20);
strcpy(p, "hello");
strncat(p, "world", 3);
printf("%s\n", p);
memset(p, 0, 20);
strcpy(p, "hello");
strncpy(p, "world", 7);
printf("%s\n", p);
return 0;
}
strcatの実装
char *strncat(char *dest, const char *src, size_t n){
size_t dest_len = strlen(dest);
size_t i;
for (i=0; i<n && src[i] !='\0'; i++)
dest[dest_len + i] = src[i];
dest[dest_len + i] = '\0';
return dest;
}
違いは次のように要約されます。
strcat
ソース文字列の終了文字が見つかるまで、ソース文字列全体を宛先文字列の末尾に連結します。strncat
連結される文字の数を制限しますn
。ソース文字列の最初の文字のみ
9. strcmp関数
#include <string.h>
int strcmp(const char *s1, const char *s2);
機能: 2 つの文字列の文字がstrcmp
辞書順に1 つずつ比較されます。比較ルールは次のとおりです。
- まず 2 つの文字列の最初の文字を比較し、それらが等しい場合は、次の文字の比較を続けます。
- 2 つの文字列の特定の位置の文字が等しくない場合、比較結果は 2 つの文字の ASCII コードの差になります。
- 文字列の 1 つが終了し (ヌル文字が検出された
\0
)、もう 1 つには文字が残っている場合、短い文字列は長い文字列より小さいとみなされます。
パラメータ:
- s1: 文字列1の先頭アドレス
- s2: 文字列 2 の最初のアドレス
戻り値:
- 等しい: 0
- より大きい: >0 オペレーティング システムが異なると、strcmp の結果は異なり、ASCII の差分を返します。
- 未満: <0
原則:
strcmp の実行ロジック: 2 つの文字列が完全に走査されるまで (異なる文字が見つからない場合、2 つは等しい)、s1 と s2 の対応する位置にある文字を 1 つずつ比較します。または 2 つの文字がある場合は、等しくない場合、比較は終了します。s1 の文字の ASCII コードが s2 の文字より大きい場合は 1 を返し、それ以外の場合は -1 を返します。
注: 一部のコンパイラには 2 つの文字列があります。
int main(){
printf("%d\n", strcmp("hello", "hello")); //前面等于后面,结果为0
printf("%d\n", strcmp("hello", "heLlo")); //前面大于后面,结果为1
printf("%d\n", strcmp("Hello", "heLlo")); //前面小于后面,结果为-1
return 0;
}
10. strncmp関数
#include <string.h>
int strncmp(const char *s1, const char *s2, size_t n);
機能: s1 と s2 の最初の n 文字のサイズを比較し、文字の ASCII コード サイズを比較します。
パラメータ:
- s1: 文字列1の先頭アドレス
- s2: 文字列 2 の最初のアドレス
n: 比較文字列の数を指定
戻り値:
- 等しい: 0
- より大きい: > 0
- 未満: < 0
演習1:
キーボードで文字列を入力し、その文字列がプログラムに設定されている文字列と等しいかどうかを判定します(比較対象は6文字まで)(大文字と小文字は区別しません)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char ch1[10];
char key[] = "A18Cd9";
memset(ch1, 0, sizeof(ch1));
printf("please input the key: %s\n", key);
scanf("%s", ch1);
printf("view the data ch1: %s\n", ch1);
return 0;
}
演習 2:
キーボードで一連の文字列を入力し、アルファベットと数字以外の文字を削除してください。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char ch1[10];
memset(ch1, 0, sizeof(ch1));
printf("plz input the data:\n");
scanf("%s", ch1);
printf("the data ch1: %s\n", ch1);
return 0;
}
11. strstr関数
strstr
は C 言語の文字列検索関数で、string 内の部分文字列の出現位置を見つけるために使用されます。
#include <string.h>
char *strstr(const char *haystack, const char *needle);
機能:文字列干し草の山内の文字列針の出現位置を検索します
。 パラメータ:
- haystack: ソース文字列の最初のアドレス
- 針: 文字列の最初のアドレスと一致します。
戻り値:
- 成功: 最初に出現した針アドレスを返します。
- 失敗: NULL
- 私たちは、文字列が別の文字列であるかどうかを判断するために strstr をよく使用します。
int main(){
char src[] = "ddddsabcd12233dsfl23dlf09a1";
char *p = strstr(src, "abcd");
printf("p = %s\n", p);
return 0;
}
12. strtok関数
strtok
C言語の文字列分割関数で、指定された区切り文字に従って文字列を分割するために使用されます。
#include <string.h>
char *strtok(char *str, const char *delim);
機能: 文字列を部分に分割します。strtok() は、パラメータ s の文字列内のパラメータ delim に含まれる分割文字を見つけると、その文字を \0 文字に変更し、行に複数の文字がある場合に最初の文字のみを \0 に置き換えます。
パラメータ:
- str: 分割する文字列へのポインタ
- delim: 分割文字列に含まれるすべての文字
戻り値:
- 成功: 分割後の文字列の最初のアドレス
- 失敗: NULL
知らせ:
- 最初の呼び出し時: strtok() にはパラメータの文字列を指定する必要があります
- 後続の呼び出しではパラメータ s が NULL に設定され、呼び出しが成功するたびに分割されたセグメントへのポインタが返されます。
int main(){
char a[100] = "abc-efg-hijk-lmn";
char *s = strtok(a, "-"); //将"-”分割的子串取出
while (s != NULL){
printf("%s\n", s);
s = strtok(NULL, "-");
printf("view the s: %s\n", s);
}
}
文字列ナレッジ ポイントの完全なコード:
int main(){
//字符串的复制 strcpy
/*char *src = "hello";
char dst[10];
strcpy(dst, src);
printf("%s\n", dst); //复制
char a[4];
char b[4];
strcpy(b, "hello");
printf("b: %s\n", b);
printf("a: %s\n", a);*/
/*char *src = "hello\0world";
char dst[10];
//char *dst;
//dst = malloc(10);
memset(dst, 'A', 10);
printf("dst:%s\n", dst); //AAAAAAAAAA
strncpy(dst, src, 3);
printf("dst: %s\n", dst); //helAAAAAAA
char *src1 = "hello";
memset(dst, 0, 10);
strncpy(dst, src, sizeof(dst)-1);
printf("dst:%s\n", dst); //hello
int i;
for (i=0; i<10; i++)
printf("view the i: %d dst[i]: %c\n", i, dst[i]);
printf("\n");*/
//字符串的拼接 strcat
/*char dst[20];
memset(dst, 0, sizeof(dst));
char *src = "he\0llo";
strcpy(dst, "world");
strcat(dst, src);
printf("dst: %s\n", dst); //worldhe */
//字符串的对比
//strcmp函数
/*char *s1 = "hello world";
char *s2 = "hello";
printf("%d\n", strcmp(s2, s1)); //-1
char *stus[] = {"zhangsan", "lisi", "wangwu", "liusan", "huangsan"};
int i;
for (i=0; i<3; i++){
if (strcmp(stus[i], "lisi") == 0)
printf("hello, lisi: %d\n", i); //1
}
printf("view the data strncmp: %d\n", strncmp(s1, s2, 5)); //0 */
//strstr函数 查找字符串内部是否存在某个元素
/*char *stus[] = {"zhangsan", "lisi", "wangwu", "liusan", "huangsan"};
int i;
char *p;
for (i=0; i<5; i++){
//找出名字中带san的学生
if (p = strstr(stus[i], "san")){
printf("view the data, i: %d, stus[i]: %s\n", i, stus[i]);
printf("%p, %p\n", stus[i], p);
}
}*/
//字符串的分割 strtok
char data[] = {"##name=zhangsan;score=99.5;age=10##"};
//第一步用;分割
char *p;
int n = 0;
int len;
p = strtok(data, ";");
printf("view the n: %s\n", p); //##name=zhangsan
len = strlen(p);
while (*p != '=' && n<=len){
printf("n:%d\n", n);
p++;
n++;
}
if (n <= len){
p++;
char name[10];
memset(name, 0, 10);
strcpy(name, p);
printf("view the n: %d, len: %d, name: %s\n", n, len, name); //zhangsan
}
//第二次对剩下的数据使用;分割
char name[10];
int age;
float score;
while (p = strtok(NULL, ";")){
char *tmp = p;
printf("%s\n", p);
len = strlen(p);
n = 0;
while (*p != '=' && n<=len){
p++;
n++;
}
printf("view the data p: %c", p);
if (n <= len){
p++;
if (strstr(tmp, "age=") != NULL){
age = atoi(p);
printf("age: %d\n", age);
}
else if (strstr (tmp, "score=") != NULL){
score = atof(p);
printf("score: %f\n", score);
}
}
}
p = strtok(NULL, ";");
printf("view the strtok p: %s\n", p);
len = strlen(p);
n = 0;
while (*p != '=' && n<=len){
p++;
n++;
}
if (n <= len){
p++;
int age;
age = atoi(p); //18
printf("age: %d\n", age);
}
p = strtok(NULL, ";");
printf("+++++ %s\n", p);
len = strlen(p);
n = 0;
while (*p != '=' && n<=len){
p++;
n++;
}
if (n <= len){
p++;
float score;
score = atof(p);
printf("score: %f\n", score);
}
return 0;
}