第11章 字符和内存处理 一、字符数组、指针和字符串的初始化作用 二、strlen函数确定字符串有效长度 三、strcpy函数拷贝字符串.

Slides:



Advertisements
Similar presentations
C语言程序设计 主讲教师 :张群燕 电话:
Advertisements

电子成绩单项目实现.
班主任培训 高密朝阳小学 韩萍.
第一章 C语言概述 计算机公共教学部.
第九章 字串 (String).
编译原理上机实习
高级语言程序设计 C++程序设计教程(下) 2006年春季学期 与一些教材的区别 偏重理论,不去讨论某个系统的具体使用方法,但会涉及实现技术
旅游服务与管理专业 知识点7 道教教主老子圣迹 任务三 道 教 主题二 中国四大宗教 辉县市职业中等专业学校 辉县市职业中等专业学校
C语言程序设计 第十二章 位运算.
复习与总结.
高级语言程序设计 主讲人:陈玉华.
C++程序设计 第二讲 清华大学软件学院.
程序设计II 第三讲 字符串处理.
函數 授課:ANT 日期:2011/3/28.
Chap 10 函数与程序结构 10.1 函数的组织 10.2 递归函数 10.3 宏定义 10.4 编译预处理.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
程序设计专题一 结构化程序设计与递归函数 主讲教师: 刘新国.
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
QQ: 李祥 QQ: 欢迎多种方式的学习交流,祝大家学有所成.
第二章 基本元素、类型和概念 七、输出函数printf 八、输入格式转换函数scanf.
C语言 程序设计基础与试验 刘新国、2012年秋.
多维数组与指针 用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。但在概念上和使用上,多维数组的指针比一维数组的指针要复杂一些。 1. 多维数组元素的地址 先回顾多维数组的性质,可以认为二维数组是“数组的数组”,例 : 定义int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
字符串和字符数组 字符串的输入和输出 字符串的基本操作
第三节 整数类型.
第三章 数据类型、运算符与表达式.
2.1 C语言的数据类型 2.2 常量与变量 2.3 变量赋初值 2.4 各类数值型数据间的混合运算 2.5 C语言的运算符和表达式
第4章 顺序程序设计.
第0章作业: 教材P12-练习与实践 1.写出用符号’*’输出描绘汉字”大”的流程图。
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
|09 陣列.
全等和相似 什麼是全等? 形狀和大小都相同的圖形稱為全等。 什麼是相似? 形狀相同而大小並一定相同的圖形稱為相似。
C语言概述 第一章.
第1讲 C语言基础 要求: (1) C程序的组成 (2) C语言的标识符是如何定义的。 (3) C语言有哪些基本数据类型?各种基本数
C语言大学实用教程 第5章 函数与程序结构 西南财经大学经济信息工程学院 刘家芬
第2章 数据类型及表达式 本章导读 本章主要知识点 《 C语言程序设计》 (Visual C++ 6.0环境)
C语言复习3----指针.
第 二 章 数据类型、运算符与表达式.
第一章 程序设计和C语言 主讲人:高晓娟 计算机学院.
函式庫補充資料.
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
C程序设计.
第一章 C语言概述 教师:周芸.
C语言程序设计 李祥 QQ:
C++语言程序设计教程 第2章 数据类型与表达式 第2章 数据类型与表达式 制作人:杨进才 沈显君.
C程序设计.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
项目1 C程序设计起步 学习目标: 通过该项目你可以知道: C语言的用途。 C语言的基本符号和关键字。 C语言程序的结构及特点。
第2章 数据类型、运算符与表达式 本章要点: 基本数据类型 常量和变量 算术运算符和算术表达式 关系运算符和关系表达式
第7章 程序的结构 四、生存期与存储属性 五、extern关键字与外部连接属性 六、static关键字与内部连接属性.
第2章 基本数据及其运算 本章学习的目标: 1、掌握基本数据的各种表示,基本数据常数的书写方法;
第一章 C语言概述 目录 什么是语言、程序 C语言的历史与发展 C语言的书写形式与程序结构 运行C语言的步骤与方法
第二章 类型、对象、运算符和表达式.
第2章 数据类型与表达式 学习目的与要求: 掌握C 语言的基本数据类型及使用方法 掌握C程序中常用的运算符和表达式 了解数据类型的转换.
第二章 基本数据类型 ——数据的表示.
#include <iostream.h>
第3章 最简单的C程序设计 3.1 顺序程序设计举例 3.2 数据的表现形式及其运算 3.3 C语句 3.4 数据的输入输出.
Introduction to the C Programming Language
第十二章 位运算.
C/C++基礎程式設計班 字元與字串 講師:林業峻 CSIE, NTU 3/14, 2015.
第二章 数据类型、运算符和表达式 §2.1 数据与数据类型 §2.2 常量、变量和标准函数 §2.3 基本运算符及其表达式 目 录 上一章
Introduction to the C Programming Language
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
基本資料型態 變數與常數 運算子 基本的資料處理 授課:ANT 日期:2014/03/03.
C 程式設計— 字元與字串 台大資訊工程學系 資訊系統訓練班.
字串 第10章 part I 8/30/2019.
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

第11章 字符和内存处理 一、字符数组、指针和字符串的初始化作用 二、strlen函数确定字符串有效长度 三、strcpy函数拷贝字符串

一、字符数组、指针和字符串的初始化作用 1. 字符数组、指针和字符串的初始化作用 C++把类型char、 signed char和 unsigned char视 为重载意义上不同的类型。 char用于定义字符变量,字符变量本身又可提升为整 型变量,为了与整型变量接口的需要,字符便分成有符号 signed char的和无符号unsigned char的。 有符号整数可带符号进行高位扩展,无符号数扩展时 高位以0进行数据填充。

char型变量是有符号还是无符号的,C和C++语言并未 对此明确规定。 因此一般不将char变量当作一字节的整型变量进行算 术运算。在微软的编译器中char视为有符号的。 字符是构成计算机信息交流的基本单位,程序是用一序 列串在一起的有意义的字符构成的,由此形成文本字符串。 字符在编程的意义上是通过关键字char定义的变量, 称为字符变量,字符数组是每一个元素都是字符构成的数 组。 在大多数情形下char、 signed char和 unsigned char 定义的变量具有相同的特性,但在实际编程中依然习惯采用 char类型处理字符、字符数组和字符串。

字符数组本身最后一个元素不必是其值为0的元素。例如: char c[ ]={33,34,35,36,37}; 局部范围内可以等价地写为: char c[5]; c[0 ]=‘!’;c[1]=‘\“’; c[2 ]=‘#’; c[3 ]=‘$’; c[4]=‘%’; 也可以用单引号一个一个的初始化字符数组,但此种用 法略嫌繁琐,但这种方法可以输入不可见字符。例如: char nodisplay [ ]= {'\a','\n','\t','\r','\0'}; //响铃、换行、水平制表、回车与空字符 可等价地改写为: char nodisplay[5 ]={7,10,9,13,0};

值得注意不以 0结尾的字符数组在参入系统提供的字符 串操作函数运算时可能会出现一些意外,因为这些函数基本 上内嵌如下的循环代码: while (*dest=*source) {;...;dest++; source++;...;} 循环的控制条件是以 0 为基准的,遇 0就结束循环,不 然则继续循环,因此记住这一点就可以放心地使用字符数组 是否要以零结尾。 C/C++的字符串是双引号括起来的字符序列。例如字符串 "abc"只有3个字符,但存储这个字符串需要4个字节的内 存,在c字符之后添补一个结束字符‘\0’,字符‘\0’的ASCII码 值是0,它是一个不可显示的字符,作为结束判断的过滤条 件。字符'0'的ASCII码值是48。

字符串常数可以初始化字符指针,也可初始化 [例] 无结尾字符'\0'的数组输出显示的结果是不确定的 # include<stdio.h> void main(void) { char c[ ]="abc"; printf ("c->%p->%s,sizeof (c)=%d\n", c,c,sizeof (c)); } //输出:c->0065FDF4->abcd8??,sizeof(c)=4 字符串常数可以初始化字符指针,也可初始化 字符数组,但作用不同。

# include<stdio.h> void main (void) { char* s="123456789"; [例] 字符串初始化指针和数组的差异 # include<stdio.h> void main (void) { char* s="123456789"; printf ("s->%p:%s,%s sizeof (s)=%d\n",s,s,s+4,sizeof(s)); char c[ ]="abcdefghi"; printf ("c->%p: %s, %s sizeof (c) = %d\t",c,c,c+7,sizeof(c)); for (int k=0;k<9;k++) printf ("%c,",s[k]); printf ("%d\n",s[9]); } //程序运行输出结果: s->00420FA0:123456789,56789 sizeof (s)=4 c->0065FDE8:abcdefghi,hi sizeof(c)=10 1,2,3,4,5,6,7,8,9,0

定义语句 char c[ ]=“abcdefghi”;的内存分配 s= 00420FA0 s+4 全局数据区 c= 0065FDE8 c+7 堆栈数据区 局部字符指针s的定义和初始化语句{char*s="123456789";} 可以分解为: char* s; s="123456789"; 1 2 3 4 5 6 7 8 9 ‘\0’ 定义语句 char* s=“123456789”;的内存分配 a b c d e f g h I ‘\0’ 定义语句 char c[ ]=“abcdefghi”;的内存分配

表示s是一个仅占4字节内存的局部变量,指针s可以指 向任意的字符变量。 字符串常数“123456789”需要10字节的内存安放。编 译器对于这样的字符串专门安排在全局数据区,这样的字符 串常数区为const Data区。 指针s获得该字符串的首地址00420FA0。 此时隐含着: s[0]= '1', s[1]= '2', s[2]= '3', s[3]= '4', ..., s[8]= '9', s[9]= '\0' 定义语句 {char c[ ]="abcdefghi";} 等价于: char c[ ]={'a','b','c','d','e','f','g','h','i','\0'};

字符数组c是局部数组,字符数组在main函数的堆栈空 间,其首地址为0065FDE8。 相似的字符串初始化形式对应的含义是不同的: 初始化字符数组的字符串是初始化列表的洗练形式,字 符数组c的内存区域可以更新。 初始化字符指针的字符串是只读字符串,指针指向字符 串的首地址。 只读字符串占住的全局const Data区不应遭到覆盖的违 规操作。

定义语句 {char c[10 ]="abcd";} 相当于数组的截断初始化形式: char c[ ]={'a','b','c','d', '\0',0,0,0,0,0}; 不能写成: char c[10 ]; c[10]= "abcd"; 字符元素相当于一字节的整型变量,字符串对应一个地 址,等号两边数据类型是不平级的。

[例] 从屏幕读取文本串到字符数组中 %s转换说明符要求char*型的指针参数,格式字符s读取 直到下一个空白字符的所有字符, 在后面添加‘\0’字符。为存 储读取的文本串和终止字符‘\0’,字符数组应足够长。 #include<stdio.h> void main (void) { char a[12],b[6],*p=a; printf ("键入文本串\n"); scanf ("%s %s", a,b); printf ("%s, %s\n", a,b); scanf ("%s ",p); printf ("%s \n",a); }

程序运行交互结果: 程序另一次运行交互结果: 键入文本串 键入文本串 12345 6789 12345 6789 12345, 6789 12345,6789 12345 6789 12345 6789 12345 12345 空格前的字符串存入“12345”存入数组a,空格后的字符串 “6789”存入数组b。相当于初始赋值: char a[12]= "12345"; char b[6]= "6789"; scanf ("%s",p)从屏幕读取文本串放入p指针指向的充 裕的内存空间。如果p指针指向的数组内存不够容纳键入的 文本串或p指针指向系统为字符串常数分配的静态const区 域,运行产生不可预料的结果。

[例] 字符串初始化二维字符数组 #include <stdio.h> void show (char*p) //输出以p定位的其后5个字符的十进制数 { int k=0; //不要求实参字符指针指向'\0'结尾的字符串 while( k<5) printf ("%d,",p[k++]); } void main (void) { char a[ ][5]={"1","23"}; char b[2][5]= {49,0,0,0,0,50,51,0,0,0}; show (a[0]); show (a[1]); printf ("\n"); //输出49,0,0,0,0,50,51,0,0,0, show (b[0]); show (b[1]); //输出 49,0,0,0,0,50,51,0,0,0,}

[例]二维数组初始化完整形式 # include<stdio.h> extern void f (char s[3][5],int n); void main (void) { char s[ ][5]={{' ',' ','*',' ',' '},{' ','*',' ','*',' '}, {'*','*','*','*','*'}}; f (s,0); printf ("\n"); f(s,1); }//结果如下: 32,32,42,32,32,32,42,32,42,32,42,42,42,42,42 * * * *****

void f (char s[3][5], int n) { for (int j=0; j<3; j++) { for (int k=0; k<5; k++) if (n==1) printf ("%c", s[ j ][ k ]); else printf ("%d,", s[ j ][ k ]); printf ("\n"); }

[例] 二维数组初始化截断形式 # include<stdio.h> extern void f (char s[3][5],int n); void main (void) { char b[ ][5]= {{' ',' ','*'},{' ','*',' ','*'}, {'*','*','*','*','*'}}; f (b,0); printf ("\n");f(b,1); } //设执行文件为a.exe 结果如下: 32,32,42,0,0,32,42,32,42,0,42,42,42,42,42, * * * *****

[例] 字符串初始化字符指针数组和二维字符数组 # include<stdio.h> void main(void) { char *pa[ ]= {"a","bc","def","higk"}; int n=sizeof (pa)/sizeof (pa[0]); int k; for (k=0;k<n;k++) printf ("%p->%s ",pa [ k ], pa [ k ]); printf ("\nsizeof(pa)=%d, sizeof (pa[0]) = %d\n", sizeof(pa),sizeof(pa[0])); char ca[ ][5] = {"1","23","456","7890"}; n = sizeof (ca)/sizeof (ca [0]); printf ("sizeof(ca)=%d,sizeof(ca[0])=%d\n", sizeof(ca),sizeof(ca[0])); for ( k=0;k<n;k++) printf ("%p->%s ",ca [ k ],ca[ k ]); }

全局内存区的数据是可索引的,局部变量对于上层主控 函数是不可操纵的。 [例] 字符串初始化局部二维字符数组与生存期 # include<stdio.h> char* sa (int n) //返回char*型指针值的函数 {//static char ca[ ][5]={"1","23","456","7890"}; return ca [n]; } void main(void) { for (int k=0;k<4;k++) printf ("%p->%s ", sa(k), sa(k));

该程序运行输出的结果是残缺的(输出局部数组的地 址,局部数组的内容是不确定的): 0065FD84-> *e 0065FD89-> 0065FD8E-> 0065FD93-> 如果在局部变量ca前加上static关键字则输出结果为: 004232F8->1 004232FD->23 00423302->456 00423307->7890

[例] 字符串初始化指针数组与生存期 # include<stdio.h> char* ga(int i) { char *pa[ ]={"a","bc","def","higk"}; return pa[i]; } void main(void) { for (int k=0; k<4; k++) printf ("%p->%s ",ga (k), ga (k)); //程序运行输出结果: 00420080->a 0042007C->bc 00420070->def 00420FD4->higk

[例] 二维字符数组行地址初始化指针数组 # include<stdio.h> char* ca(int i) { char c[ ][5]={"a","bc","def","higk"}; char* pa[ ]={c[0],c[1],c[2],c[3]}; return pa[i]; } void main (void) { for (int k=0;k<4;k++) printf ("%p->%s ",ca(k),ca(k)); 程序输出结果是残缺的: 0065FD84-> *e 0065FD89-> 0065FD8E-> 0065FD93->

[例] 返回char**指针值的函数 # include<stdio.h> char** ppn (char *pp[ ],int n) { return pp+n; } void main (void) { char *pa[4]= { "a","bc","def","ghijk“ }; for (int k=0; k<4; k++) printf ("%s",*ppn(pa,k)); } //输出:abcdefghijk

二、strlen函数确定字符串有效长度 作用: 计算入口字符串的净长度(结尾字符'\0'前的字符个数) 函数原型: size_t strlen(const char*s); 作用: 计算入口字符串的净长度(结尾字符'\0'前的字符个数) unsigned int strlen1(const char*s) /**函数的要点说明**/ { unsigned int length=0; // length纪录字符串的个数 while(*s!='\0') {s++;length++;} //长度length中不含'\0' return length; //返回不含结尾符的字符串长度 } //字符数组若无结尾字符则结果是游移的

#include<string.h> #include<stdio.h> void main (void) { char c[ ]="ab\0d"; printf ("strlen (c)=%d,sizeof (c)=%d,%s\n", strlen1 (c),sizeof(c),c); c[2]='c'; printf ("strlen(c)=%d,%s\n",strlen(c),c); c[4]='e'; printf ("strlen (c)=%d,%s\n",strlen(c),c); printf ("strlen (ab\053d)=%d,%s\n", strlen ("ab\053d"),"ab\053d"); }

//输出结果: strlen (c)=2,sizeof(c)=5,ab //由sizeof获得字符数组的长度 strlen (c)=4,abcd //对于 char c[ ]="abcd";存在sizeof(c) = strlen(c)+1 strlen (c)=11,abcde?????? //结果strlen(c)=11是不确定的 strlen (ab+d)=4,ab+d // \053是字符+的八进制ASCII码 对于 {char d[10]="12345"; char *s="12345678";} 存在 strlen(d)=5,sizeof(d)=10,strlen(s)=8, sizeof(s) = sizeof (char *) = 4 或2。当若干字符串用空格 分隔的时候,相邻的字符串合为一体。

这种合并相邻字符串的方式可将一行写不下的长字符串 分散到多行。例如: char c[ ]="12 34" "56\n"; 相当于 char c[ ]="12 3456\n"; char* s="abcd" " ef\n" ; 相当于 char* s="abcd ef\n" ; 因此: printf ("%d,%d,%s",strlen (c),sizeof (c),c); 输出: 8,9,12 3456 printf ("%d,%d,%s",strlen (s),sizeof (s),s); 输出: 8,4,abcd ef

三、strcpy函数拷贝字符串 函数原型: char* strcpy(char *dst,const char*src); 作用: 将源串src中的字符拷贝到目标串dst中 char* strcpy1(char *dst,const char*s) { char * p=dst; while ((*p=*s) !='\0') {p++; s++;} *p='\0'; return dst; } #include<string.h> #include<stdio.h> void main (void) { char b[ ]="while Hsiang river is flowing northward" ; char * c=new char [sizeof(b)]; printf (“%s\n”,strcpy1 (c,b)); delete [ ] c; }

说明: 上面while((*p=*s) !=‘\0') {p++; s++;}循环流程是明确的 无歧义的,先将原字符串中的字符拷贝给目标内存的相应位 置,判断是否遇到结尾字符,如果未遇到结尾字符 则继续 拷贝。 这个循环可改为 [while(*s!=‘\0’) *p++=*s++;], 语句 [*p++=*s++;] 分解为 {*p=*s;p++;s++} 但不应改为下面的循环: while((*p++=*s++) !='\0') ; //循环体为空语句

不同的编译器对循环语句中条件判断中的表达式 *p++=*s++有不同的分解方法。[while((*p++=*s++) !='\0');] 未必分解为while((*p=*s) !=‘\0’) {p++; s++;} 例如:vc6.0中对空语句表示的循环运行时弹出Debug Error错误。因此不要在循环语句的条件表达式中出现形如 while (p[k++]=s[i++]),for(;*p++;),while(*p++=*s++)等分解 次序含糊的表达式s[k++],*p++等。 while (e!=0)等价于while(e),while (*s!=‘\0’)可以改 为while(*s)。

请打开“第11章 (2) .ppt”