謹記
一個人的潛力有多大、能力有多強,是一個未知數(shù),因為我相信能力就是干出來的,以前讀過一本書《能力就是干出來的》,這本書就講述了化保力人生最艱難和輝煌的那段時間,一個農(nóng)村家境非常不好的他,經(jīng)理了怎樣的磨練才有明天的成功,今天推薦大家可以去品讀一下這本書,讀完這本書過后,你會覺得命運的改變就在那一瞬間,一切的一切都不在是借口,都將不在是理由。因為,能力就是干出來的,所以,積極的努力奮斗吧,你的能力有多大就在于你干多少實實在在有意義的事。
前言
上一篇文章已經(jīng)介紹了C語言數(shù)組中一維數(shù)組、二維數(shù)組的相關(guān)知識點,通過上篇文章讀者能夠收獲關(guān)于數(shù)組的概念、定義、初始化、排序等知識點,今天向讀者展示的也是C語言數(shù)組相關(guān)的知識點,那就是字符數(shù)組以及字符串的一些用法。
字符數(shù)組
1、字符數(shù)組的定義
有一定順序關(guān)系的若干個字符型變量的集合,就是字符數(shù)組。可以是一維的,也可以是多維的。字符數(shù)組具有普通數(shù)組的性質(zhì),又有一些特殊的性質(zhì)。
字符數(shù)組的定義形式如下:
char c[7];
char ch[4][3];
字符數(shù)組初始化方式
1、和普通的數(shù)組相同,逐個為數(shù)組元素賦值
char ch[4] = {‘a(chǎn)’, ‘b’, ‘c’, ‘\0’};
2、使用字符串常量來賦值
char ch[10] = {"abcdefghjk"};
這里需要注意下:用字符串來初始化字符數(shù)組,字符串結(jié)尾是以“\0”結(jié)尾,上面看起來只有10個字母,但字符串隱含了結(jié)束標志\0,相當于11個字母,越界了。(字符串后面講解)
遍歷字符數(shù)組
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[]) {
char ch[10] = {"abcdefghjk"};
printf("%lu\n",sizeof(ch));
for (int i = 0 ; i <sizeof(ch) / sizeof(char); i++) {
printf("%c\n",ch[i]);
}
return 0;
}
結(jié)果:
10
a
b
c
d
e
f
g
h
j
k
Program ended with exit code: 0
3、不完全初始化
char ch[5] = {"qw"};
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[]) {
char ch[5] = {"abc"};
printf("%lu\n",sizeof(ch));
for (int i = 0 ; i <sizeof(ch) / sizeof(char); i++) {
if (ch[i] != NULL) {
printf("%c\n",ch[i]);
}
}
return 0;
}
運行結(jié)果:
5
a
b
c
Program ended with exit code: 0
這里雖然字符數(shù)組初始化的時候只有3個元素,在進行數(shù)組遍歷的時候,可以看到,ch[3]和ch[4]是為空的,但是在內(nèi)存空間分配的時候,還是有內(nèi)存空間的,只不過里面沒存東西而已,所以對數(shù)組求sizeof的時候是5。
字符串
在C語言中,嚴格上講師沒有字符串這個數(shù)據(jù)類型的,不管是原生的還是構(gòu)造的數(shù)據(jù)類型,但是為何在程序員心中是有字符串這個類型的,首先,我們知道C語言是一個面向過程的一門語言,而基于C語言更高級的語言比如Ojective-C是面向?qū)ο蟮恼Z言,而在高級語言中有字符串這一類型,所以,在C語言中,程序員可以通過字符數(shù)組模擬字符串。字符串指的是以‘\0’作為結(jié)束字符的一組字符,因此當把一個字符串存入一個數(shù)組時,也把結(jié)束符'\0'存入數(shù)組,并以此作為該字符串是否結(jié)束的標志。如何定義字符串變量, 由于字符串是同一種類型的數(shù)據(jù)組成, 并且是有序的而數(shù)組就是用于存儲很多同一種類型的有序數(shù)據(jù), 所以可以使用數(shù)組來保存字符串
// 注意: 字符串變量和普通的字符數(shù)組有一定的區(qū)別
// C語言規(guī)定, 字符串必須以\0結(jié)尾(作為字符串的結(jié)束符號), 所以字符串變量的元素個數(shù)比字符數(shù)組的元素個數(shù)多一個 \0
char str[] = "lnj"; // 字符串變量 l n j \0
printf("str size = %lu\n", sizeof(str));
char charValues[] = {'l', 'n', 'j'}; // 字符數(shù)組 , 這個并不是字符串, 而是字符數(shù)組
printf("charValues size = %lu\n", sizeof(charValues));
int num = 10;
float floatValue = 10.1f;
double doubleValue = 9.9;
char charValue = 'm';
printf("%i, %f, %lf, %c\n", num, floatValue, doubleValue, charValue);
字符串輸入和輸出
前面我們學習過scanf和printf,利用C語言中的循環(huán)控制語句,我們可以逐個輸出,格式化采用“%s”。
#include <stdio.h>
#define N 20
int main(int argc, const char * argv[]) {
char s1[]="hello world";
char s2[N];
printf("String1: %s\n", s1);
printf(">");
scanf("%s",s2);
printf("String2: %s\n",s2);
return 0;
}
輸出結(jié)果情況一:
String1: hello world
>qweerrttddsrtyydddd
String2: qweerrttddsrtyydddd
Program ended with exit code: 0
輸出結(jié)果情況二:
String1: hello world
>ni hao suny
String2: ni
Program ended with exit code: 0
這里有幾種情況,讀者可以去模擬一下
結(jié)論:輸入一個字符串,并打印出來。需要注意的是,字符數(shù)組的長度定義為N,在輸入字符時,最多能輸入 N-1個字符,以留出一個字節(jié)用于存放字符串結(jié)束標志'\0'。
從第二種輸出結(jié)果的情況,可以看出,當用scanf函數(shù)輸入字符串時,以空格作為字符串的結(jié)束符。因次,若輸入字符串中含有空格,空格后面的字符將不能存到數(shù)組中
字符串常用方法一
#include <stdio.h>
#include <string.h>
int myStrlen(char str[]);//聲明函數(shù)
int myStrlen2(char str[], int length);
int main(int argc, const char * argv[]) {
// 1.如何輸出字符串
/*
// 1.1可以使用printf的%s占位符來輸出
// 弊端 : 如果想要換行, 必須加上\n
// 優(yōu)點 : 可以自定義格式化需要輸出的字符串, 也就是可以按照我們需要的格式來輸出
char str[] = "ljk";
printf("name = %s!!!!\n", str);
printf("-------\n");
// 1.2可以使用puts函數(shù)來輸出
// 優(yōu)點: 可以自動換行
// 缺點: 不可以自定義格式, 只能原樣輸出
puts(str);
printf("-------\n");
*/
/*************************分割線*******************************/
// 2.如何輸入字符
/*
// 2.1利用scanf接收字符串的注意點
// scanf接收字符串, 會以空格 , tab, 回車作為結(jié)束符號, 也就是說利用scanf接收字符串時, 字符串中不能出現(xiàn)空格, tab, 回車
printf("請輸入一個字符串\n");
char buf[10];
scanf("%s", buf);
printf("buf = %s\n", buf);
printf("-------\n");
// 2.2利用gets接收字符串
// warning: this program uses gets(), which is unsafe.
// 如果使用gets接收字符串, 系統(tǒng)會提示我們正在使用一個不安全的方法接收字符
// 優(yōu)點: 如果利用gets接收字符串 , 可以在字符串中輸入空格, tab
printf("請輸入一個字符串\n");
char buf2[10]; // lnj c
gets(buf2);
printf("buf = %s\n", buf2);
printf("-------\n");
*/
/*************************分割線*******************************/
// 3.如何計算字符串的長度
// 0123
char str[] = "lnj cool"; // 3
// int length = sizeof(str) / sizeof(str[0]) - 1;
// strlen的原理: 從傳入的地址開始逐個取出字符串, 每取出一個就讓計數(shù)器+1. 直到遇到\0為止
// size_t size = strlen(str); // 計算出來的結(jié)果不包括\0
// int size = myStrlen(str);
int length = sizeof(str) / sizeof(str[0]);
int size = myStrlen2(str, length);
printf("length = %lu\n", size);
for (int i = 0; i < size; i++) {
printf("str[%i] = %c\n", i , str[i]);
}
return 0;
}
//函數(shù)實現(xiàn)(后面會詳細講解函數(shù))
int myStrlen2(char str[], int length)
{
// 1.定義變量記錄取出了多少個字符
int count = 0;
// 2.遍歷字符數(shù)組
for (int i = 0; i < length; i++) {
if (str[i] != '\0') {
count++;
}
}
return count;
}
// 自定義一個strlen函數(shù)
int myStrlen(char str[])
{
// 1.定義變量記錄取出了多少個字符
int count = 0;
// 2.遍歷字符數(shù)組
while (str[count] != '\0') {
count++; // 1 2 3
}
return count;
}
字符串常用方法二
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[]) {
// 1.字符串拼接
/*
// 原理 : 首先遍歷第一個字符串,直到遇到\0為止, 然后取出第二個字符串中的字符, 從\0的位置開始添加, 添加完畢之后再在最后添加一個\0
char str1[7] = "lnj"; // l n j c o o l \0
char str2[10] = " cool";
printf("拼接前: %s\n", str1);
// dest : 目標 src : 源
// 將src中的數(shù)據(jù)拼接到dest后面
// 注意: 要想使用字符串拼接函數(shù), 那么dest必須是一個數(shù)組, 并且數(shù)組的長度必須大于拼接之后的長度 \
如果dest數(shù)組的長度, 不能完全存放dest+src+\0, 那么就會報錯
// strcat(str1, str2);
// char * 相當于dest const char * 相當于src size_t 需要拼接的個數(shù)
// 為了避免拼接之后超出str1的存儲范圍, 那么可以動態(tài)計算str2中需要拷貝幾個到str1后面不會超出
// str1能夠存放的元素個數(shù) - str1已經(jīng)存放的個數(shù) - \0
size_t length = sizeof(str1) / sizeof(str1[0]) - strlen(str1) - 1;
printf("length = %lu\n", length);
strncat(str1, str2, length);
printf("拼接后: %s\n", str1);
*/
/*************************華麗的分割線*******************************/
// 2.字符串拷貝函數(shù)
/*
char str1[4] = "hello";
char str2[] = "cool";
printf("拷貝前 : str1 = %s\n", str1);
// char * 目標, const char * 源
// strcpy函數(shù)會將源的數(shù)據(jù)拷貝到目標中, 并且會覆蓋掉目標中原有的數(shù)據(jù)
// 目標的容積必須能夠存放拷貝的數(shù)據(jù), 如果容積不夠會報錯
// strcpy(str1, str2);
// char * 目標, const char * 源 size_t 需要拷貝幾個
// 注意: 拷貝操作是逐個替換, 拷貝了幾個就替換幾個
// str1能夠存放元素的個數(shù) - 1是給\0留出位置
int length = sizeof(str1) / sizeof(str1[0]) - 1;
strncpy(str1, str2, length);
printf("拷貝后 : str1 = %s\n", str1);
*/
/*************************分割線*******************************/
// 3.字符串比較函數(shù)
/*
char str1[] = "aac"; // a a
char str2[] = "abc"; // a b
// strcmp它會對傳入的字符串進行比較, 比較完畢之后會返回一個整型的值給我們
// 1、該值等于0,那么證明兩個字符串相等
// 2、該值小于0, 那么證明str1小于str2
// 3、該值大于0, 那么證明str1大于str2
// strcmp的比較原理: 取出字符串中的每一個字符進行逐個比較, 如果發(fā)現(xiàn)不相等就不會繼續(xù)往下比較
int res = strcmp(str1, str2);
printf("res = %i\n", res);
*/
return 0;
}
總結(jié)
希望讀者能夠良好的掌握字符數(shù)組和字符串,對字符串常用的方法要有所了解和運用,對前面所學的知識要連貫運用。
結(jié)尾
最后,希望讀者在讀文章的時候發(fā)現(xiàn)有錯誤或者不好的地方,歡迎留言,我會及時更改,感謝你的閱讀和評論已經(jīng)點贊收藏。