字符串是有序字符的集合,C 语言中没有字符串的概念,而是通过特殊的字符数组模拟字符串,是以'\0'结尾的字符数组。

1.字符数组与字符串

(1)在 C 语言中,字双引号引用的单个或多个字符是一种特殊的字面量,被存储于程序的全局只读存储区,在本质上为字符数组,编译器自动在结尾加上'\0'字符。

#include <stdio.h>

int main()
{ char ca[] = {'H','e','l','l',''}; //栈,字符数组,注意没有\0
char sa[] = {'W','o','r','l','d','\0'}; //栈 char ss[] = "Hello world!";//栈。从语义上看,要用"Hello World!"这个
//字符数组去初始化ss数组,编译器会直接
//用这个字符数组的每个元素,去初始化栈上
//ss数组中的元素。作为优化,"Hello World!"
//这个字符串就可以不必保存在全局只读区,
//而只出现在栈上。因此ss[0] = 'h'
//这个的语句是合法的。 char* str = "Hello World!"; //全局只读存储区,str[0]='h'是非法的 printf("%s\n", ca); //输出Hello及后面的内容,直到在内存中遇到\0
printf("%s\n", sa); //输出Hello World!
printf("%s\n", ss); //输出Hello World!
printf("%s\n",str); //输出Hello World! ss[] = 'h'; //栈,合法
printf("%s\n", ss); //输出Hello World! //str[0] = 'h'; //全局只读存储区,非法
printf("%s\n", str); //输出Hello World! return ;
}

(2)字符串字面量的本质是一个数组,如“Hello World!”是一个无名的字符数组

(3)字符串字面量可以看作常量指针

(4)字符串字面量中的字符不可改变

(5)字符串字面量至少包含一个字符,即'\0'

#include <stdio.h>

int main()
{ //本质上字符串字面量是一个字符数组,形如"Hello World!"是一个
//无名的字符数组。
char b = "abc"[]; //合法,指向字符数组的第0个元素,即a
char c = *("" + );//合法,取出字符数组第2个元素,即2
char t = *""; //字符串字面量至少包少一个\0,即t='\0' printf("%c\n", b); //'a'
printf("%c\n", c); //'2'
printf("%d\n", t); // printf("%s\n","Hello");
printf("%p\n","World"); //输出字符串字面量的地址(全局区中) return ;
}

2.字符串的长度

(1)字符串的长度就是字符串所包含字符的个数

(2)字符串长度指的是第一个'\0'字符前出现的字符个数,通过'\0'结束符来确定字符串的长

(3)函数 strlen 用于返回字符串的长度(不含'\0')。

#include <stdio.h>
#include <string.h> int main()
{ char s[]="Hello\0World!";
int i = ; //输出s数组中所有的元素
for(i=; i<sizeof(s)/sizeof(*s); i++)
{
printf("%c",s[i]);
} printf("\n"); printf("%s\n",s);//输出:Hello,因为遇到第1个\0就结束 printf("%d\n",strlen(s)); //输出5
printf("%d\n",strlen("")); // return ;
}

3.snprintf 函数(gcc 下为 snprintf,vc 为_snprintf)

snprintf 函数本身是可变参数函数,原型如下:

int snprintf(char* buffer,int buf_size,const char* format,...);

当函数只有 3 个参数时,如果第 3 个参数没有格式化信息,函数调用是没有问题的;相反如果第 3 个参数包含了格式化信息,但缺少后续对应参数,则程序行为不确定。格式化信息必须与变参个数相匹配。

#include <stdio.h>

int main()
{
char buf[] = { };
//char src[] = "hello %s";//字符串中包含格式化信息,输出会异常
char src[] ="hello world!";//不含格式化信息,则正常输出 //因src中含有格式化信息,所以这种行为不确定,
//输出hello会,后面可能跟一个奇怪的字符串。
snprintf(buf, sizeof(buf), src); printf("buf = %s\n", buf); return ;
}

4.字符串长度的计算

(1)字符串相关的函数均以第一个出现的'\0'作为结束符

(2)编译器总是会在字符串字面量的末尾添加'\0'。

(3)字符串字面量的本质为数组

(4)字符串、字符数组、字符指针是不同的 3 个概念。

#include <stdio.h>
#include <string.h> int main()
{
#define STR "Hello, \0World!\0" char* src = STR;
char buf[] = {}; snprintf(buf, sizeof(buf), src); printf("strlen(STR) = %d\n", strlen(STR)); //
printf("sizeof(STR) = %d\n", sizeof(STR)); //16,字符串字面量变质为
//字符数组,并编译器
//在最后加一个'\0'
printf("strlen(src) = %d\n", strlen(src)); //7,遇第1个\0结束
printf("sizeof(src) = %d\n", sizeof(src)); //4,指针大小 printf("strlen(buf) = %d\n", strlen(buf)); //7,遇第1个\0结束
printf("sizeof(buf) = %d\n", sizeof(buf)); //255,buf数组的大小 printf("src = %s\n", src); //hello, 共6个字符,含一个空格
printf("buf = %s\n", buf); //hello, 共6个字符,含一个空格 return ;
}

5.字符串相等的比较

(1)字符串之间的相等比较需要用 strcmp 完成

(2)不可直接用==进行字符串直接的比较

(3)完全相同的字符串字面量的==比较结果为 false。但一些现代编译器(如 gcc)能够将相同的字符串字面量映射同一个无名字符数组,因此==比较结果为 true。正因这个行为,所以我们不应编写依赖特殊编译器的代码!

#include <stdio.h>
#include <string.h> int main()
{
#define S1 "Hello World!"
#define S2 "Hello World!" //S1和S2存于常量区中,因两者内容完全一样,存于全局只读区。
//一些现代的编译器会将S1和S2映射到同一个字符数组中。
if(S1 == S2) //gcc、Vc下相等,bcc下不相等!
{
printf("Equal\n");
}else{
printf("Non Equal\n");
} if(strcmp(S1,S2) == ) //判断两个字符串是否相等。
{
printf("Equal\n");
}else{
printf("Non Equal\n");
} return ;
}

参考资料:
www.dt4sw.com
http://www.cnblogs.com/5iedu/category/804081.html

C语言学习笔记--字符串的更多相关文章

  1. C语言学习笔记--字符串函数

    字符串函数 需要包含头文件#include<stdio.h> strlen strcmp strcpy strchr strstr strcasestr

  2. GO语言学习笔记(一)

    GO语言学习笔记 1.数组切片slice:可动态增长的数组 2.错误处理流程关键字:defer panic recover 3.变量的初始化:以下效果一样 `var a int = 10` `var ...

  3. Haskell语言学习笔记(88)语言扩展(1)

    ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...

  4. Go语言学习笔记六: 循环语句

    Go语言学习笔记六: 循环语句 今天学了一个格式化代码的命令:gofmt -w chapter6.go for循环 for循环有3种形式: for init; condition; increment ...

  5. Go语言学习笔记二: 变量

    Go语言学习笔记二: 变量 今天又学了一招如何查看go的版本的命令:go version.另外上一个笔记中的代码还可以使用go run hello.go来运行,只是这种方式不会生成exe文件. 定义变 ...

  6. 《python基础教程(第二版)》学习笔记 字符串(第3章)

    <python基础教程(第二版)>学习笔记 字符串(第3章)所有的基本的序列操作(索引,分片,乘法,判断成员资格,求长度,求最大最小值)对字符串也适用.字符串是不可以改变的:格式化输出字符 ...

  7. 《C# 语言学习笔记》——目录

    C# 简介 变量和表达式 流程控制 3.1 布尔逻辑 3.2 goto语句 3.3 分支 3.4 循环 变量的更多内容 4.1 类型转换 4.2 复杂的变量类型 4.3 字符串的处理 函数 5.1 定 ...

  8. Go语言学习笔记(1)——顺序编程

    Go语言学习笔记这一堆主要是<Go语言编程>(人民邮电出版社)的读书笔记.中间会穿插一些零碎的点,比如源码学习之类的.大概就是这样吧. 1. 顺序编程 1.1 变量 变量的声明: var ...

  9. HTML语言学习笔记(会更新)

    # HTML语言学习笔记(会更新) 一个html文件是由一系列的元素和标签组成的. 标签: 1.<html></html> 表示该文件为超文本标记语言(HTML)编写的.成对出 ...

随机推荐

  1. hdoj1004--Let the Balloon Rise

    Problem Description Contest time again! How excited it is to see balloons floating around. But to te ...

  2. vlan 配置

    在RedHat上配置vlan: ~]$ modinfo 8021q在ethX接口上配置vlan逻辑子接口: DEVICE=ethX. BOOTPROTO=none ONBOOT=yes IPADDR= ...

  3. DEDE整站动态化或整站静态化设置方法

    简单说下的是,网站空间小而数据库还可以的话,使用动态浏览也是不错的,但是官方的程序默认的生成静态浏览的,只要一发布文章,就会自动生成静态页面,难道做发布文章还要一个一个去更改其他的设置吗?麻烦.对于采 ...

  4. python基础2 - 运算符

    3. 运算符 3.1 算数运算符 算数运算符是 运算符的一种 是完成基本的算术运算使用的符号,用来处理四则运算 运算符 描述 实例 + 加 10 + 20 = 30 - 减 10 - 20 = -10 ...

  5. Deep Learning(Ian Goodfellow) — Chapter2 Linear Algebra

    线性代数是机器学习的数学基础之一,这里总结一下深度学习花书线性代数一章中机器学习主要用到的知识,并不囊括所有线性代数知识. 2.1 基础概念 Scalars: 一个数: Vctors: 一列数: Ma ...

  6. OS X 10.11 El Capitan 三指拖动的开启方法

    触摸板的三指拖动功能已经被移到“辅助功能”中. 开启步骤: 系统偏好设置-辅助功能-鼠标与触摸板,点击下面的“触摸板选项...”按钮,勾选“启用拖拽”并且从下拉列表里选择“三指拖移” .

  7. poj 1836 LIS变形

    题目链接http://poj.org/problem?id=1836 Alignment Time Limit: 1000MS   Memory Limit: 30000K Total Submiss ...

  8. spring发布RMI服务(-)

    spring发布RMI服务 最近交流了一个项目,需要从RMI.WebService.接口文件中采集数据到大数据平台,下面自己测试了通过Spring发布RMI服务. 说明:RMI服务要求服务端和客户端都 ...

  9. 数据库Dao类BaseDao(增删改)

    package com.changim.patient.app.db; import android.content.ContentValues; import android.content.Con ...

  10. 分布式_事务_02_2PC框架raincat源码解析

    一.前言 上一节已经将raincat demo工程运行起来了,这一节来分析下raincat的源码 二.协调者启动过程 主要就是在启动类中通过如下代码来启动 netty nettyService.sta ...