C语言数组讲解(二)

谨记

一个人的潜力有多大、能力有多强,是一个未知数,因为我相信能力就是干出来的,以前读过一本书《能力就是干出来的》,这本书就讲述了化保力人生最艰难和辉煌的那段时间,一个农村家境非常不好的他,经理了怎样的磨练才有明天的成功,今天推荐大家可以去品读一下这本书,读完这本书过后,你会觉得命运的改变就在那一瞬间,一切的一切都不在是借口,都将不在是理由。因为,能力就是干出来的,所以,积极的努力奋斗吧,你的能力有多大就在于你干多少实实在在有意义的事。

前言

上一篇文章已经介绍了C语言数组中一维数组、二维数组的相关知识点,通过上篇文章读者能够收获关于数组的概念、定义、初始化、排序等知识点,今天向读者展示的也是C语言数组相关的知识点,那就是字符数组以及字符串的一些用法。

字符数组

1、字符数组的定义
有一定顺序关系的若干个字符型变量的集合,就是字符数组。可以是一维的,也可以是多维的。字符数组具有普通数组的性质,又有一些特殊的性质。
字符数组的定义形式如下:
char c[7];
char ch[4][3];
字符数组初始化方式
1、和普通的数组相同,逐个为数组元素赋值
char ch[4] = {‘a’, ‘b’, ‘c’, ‘\0’};
2、使用字符串常量来赋值
char ch[10] = {"abcdefghjk"};
这里需要注意下:用字符串来初始化字符数组,字符串结尾是以“\0”结尾,上面看起来只有10个字母,但字符串隐含了结束标志\0,相当于11个字母,越界了。(字符串后面讲解)

遍历字符数组
#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;
}
结果:
        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;
}
运行结果:
5
a
b
c
Program ended with exit code: 0
这里虽然字符数组初始化的时候只有3个元素,在进行数组遍历的时候,可以看到,ch[3]和ch[4]是为空的,但是在内存空间分配的时候,还是有内存空间的,只不过里面没存东西而已,所以对数组求sizeof的时候是5。

字符串
在C语言中,严格上讲师没有字符串这个数据类型的,不管是原生的还是构造的数据类型,但是为何在程序员心中是有字符串这个类型的,首先,我们知道C语言是一个面向过程的一门语言,而基于C语言更高级的语言比如Ojective-C是面向对象的语言,而在高级语言中有字符串这一类型,所以,在C语言中,程序员可以通过字符数组模拟字符串。字符串指的是以‘\0’作为结束字符的一组字符,因此当把一个字符串存入一个数组时,也把结束符'\0'存入数组,并以此作为该字符串是否结束的标志。如何定义字符串变量, 由于字符串是同一种类型的数据组成, 并且是有序的而数组就是用于存储很多同一种类型的有序数据, 所以可以使用数组来保存字符串

 // 注意: 字符串变量和普通的字符数组有一定的区别
 // C语言规定, 字符串必须以\0结尾(作为字符串的结束符号), 所以字符串变量的元素个数比字符数组的元素个数多一个 \0
 char str[] = "lnj"; // 字符串变量 l n j \0
 printf("str size = %lu\n", sizeof(str));
 
 char charValues[] = {'l', 'n', 'j'}; // 字符数组 , 这个并不是字符串, 而是字符数组
 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语言中的循环控制语句,我们可以逐个输出,格式化采用“%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;
}
输出结果情况一:
String1: hello world
>qweerrttddsrtyydddd
String2: qweerrttddsrtyydddd
Program ended with exit code: 0
输出结果情况二:
String1: hello world
>ni hao suny
String2: ni
Program ended with exit code: 0
这里有几种情况,读者可以去模拟一下
结论:输入一个字符串,并打印出来。需要注意的是,字符数组的长度定义为N,在输入字符时,最多能输入 N-1个字符,以留出一个字节用于存放字符串结束标志'\0'。
从第二种输出结果的情况,可以看出,当用scanf函数输入字符串时,以空格作为字符串的结束符。因次,若输入字符串中含有空格,空格后面的字符将不能存到数组中

字符串常用方法一

#include <stdio.h>
#include <string.h>
int myStrlen(char str[]);//声明函数
int myStrlen2(char str[], int length);
int main(int argc, const char * argv[]) {
    // 1.如何输出字符串
    /*
    // 1.1可以使用printf的%s占位符来输出
    // 弊端 : 如果想要换行, 必须加上\n
    // 优点 : 可以自定义格式化需要输出的字符串, 也就是可以按照我们需要的格式来输出
    char str[] = "ljk";
    printf("name = %s!!!!\n", str);
    printf("-------\n");
    // 1.2可以使用puts函数来输出
    // 优点: 可以自动换行
    // 缺点: 不可以自定义格式, 只能原样输出
    puts(str);
    printf("-------\n");
    */
    /*************************分割线*******************************/
    // 2.如何输入字符
    /*
    // 2.1利用scanf接收字符串的注意点
    // scanf接收字符串, 会以空格 , tab, 回车作为结束符号, 也就是说利用scanf接收字符串时, 字符串中不能出现空格, 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接收字符串, 系统会提示我们正在使用一个不安全的方法接收字符
    // 优点: 如果利用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的原理: 从传入的地址开始逐个取出字符串, 每取出一个就让计数器+1. 直到遇到\0为止
//    size_t size =  strlen(str); // 计算出来的结果不包括\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;
}
//函数实现(后面会详细讲解函数)
int myStrlen2(char str[], int length)
{
    // 1.定义变量记录取出了多少个字符
    int count = 0;
    // 2.遍历字符数组
    for (int i = 0; i < length; i++) {
        if (str[i] != '\0') {
            count++;
        }
    }
    return count;
}

// 自定义一个strlen函数
int myStrlen(char str[])
{
   // 1.定义变量记录取出了多少个字符
    int count = 0;
  // 2.遍历字符数组
    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中的数据拼接到dest后面
    // 注意: 要想使用字符串拼接函数, 那么dest必须是一个数组, 并且数组的长度必须大于拼接之后的长度 \
    如果dest数组的长度, 不能完全存放dest+src+\0, 那么就会报错
//    strcat(str1, str2);
    
    // char * 相当于dest  const char * 相当于src size_t 需要拼接的个数
    // 为了避免拼接之后超出str1的存储范围, 那么可以动态计算str2中需要拷贝几个到str1后面不会超出
//                  str1能够存放的元素个数            -   str1已经存放的个数  - \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.字符串拷贝函数
    /*
    char str1[4] = "hello";
    char str2[] = "cool";
    printf("拷贝前 : str1 = %s\n", str1);
    // char * 目标, const char * 源
    // strcpy函数会将源的数据拷贝到目标中, 并且会覆盖掉目标中原有的数据
    // 目标的容积必须能够存放拷贝的数据, 如果容积不够会报错
//    strcpy(str1, str2);
    
    // char * 目标, const char * 源 size_t 需要拷贝几个
    // 注意: 拷贝操作是逐个替换, 拷贝了几个就替换几个
    //     str1能够存放元素的个数 - 1是给\0留出位置
    int length = sizeof(str1) / sizeof(str1[0]) - 1;
    strncpy(str1, str2, length);
    printf("拷贝后 : str1 = %s\n", str1);
    */
    /*************************分割线*******************************/
    
    // 3.字符串比较函数
    /*
    char str1[] = "aac"; // a a
    char str2[] = "abc"; // a b
    // strcmp它会对传入的字符串进行比较, 比较完毕之后会返回一个整型的值给我们
    // 1、该值等于0,那么证明两个字符串相等
    // 2、该值小于0, 那么证明str1小于str2
    // 3、该值大于0, 那么证明str1大于str2
    // strcmp的比较原理: 取出字符串中的每一个字符进行逐个比较, 如果发现不相等就不会继续往下比较
    int res = strcmp(str1, str2);
    printf("res = %i\n", res);
     */
    
    return 0;
}

总结

希望读者能够良好的掌握字符数组和字符串,对字符串常用的方法要有所了解和运用,对前面所学的知识要连贯运用。

结尾

最后,希望读者在读文章的时候发现有错误或者不好的地方,欢迎留言,我会及时更改,感谢你的阅读和评论已经点赞收藏。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 数组在程序设计中,为了处理方便, 把具有相同类型的若干变量按有序的形式组织起来。这些按序排列的同类数据元素的集合称...
    朱森阅读 3,780评论 2 13
  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,387评论 3 44
  • 在c语言中,字符串是用字符数组来存储的(并不像c++或者java等语言中有单独的string类型), 存放时在字符...
    朱森阅读 1,522评论 0 2
  • 本文转自:http://www.cnblogs.com/lidabo/p/5225868.html 1)字符串操作...
    XiaohuiLI阅读 9,358评论 0 0
  • 引自STM32的时钟系统RCC详细整理
    道无显隐阅读 591评论 0 2