计算机程序设计实训记录(5)
前面关于排序算法的任务没有完成,我...我实在不知道怎么办了QAQ
不管了,跳过这个写后面的吧。
C-字符串处理
字符串处理简介
字符串是程序设计中常用的一种数据。然而 C 语言中的字符串(常称为 C-字符串)的概念、操作却涉及到数组、指针、函数等概念。也正是这个原因,使得有关 C-字符串的练习成为理解和掌握数组、指针、函数操作的极佳素材。
C-字符串按字符数组的形式存放在计算内存中,并且以特殊字符'\0'作为串结束标志。其中的字符数组被称为字符串的 容器,一般数组、动态数组(即堆数组)或常量数组都可能成为 C-字符串的容器。C-字符串的容器常常需要程序员花额外的精力进行管理,特别是需要保证有“足够大”的容量。由于 C-字符串在内存中连续存放,又有串结束标志字符,并且认为其容器已经设置妥当且容量“足够大”,在这样的前提下,在 C 语言程序中,常将char*或const char*类型理解为 C-字符串(变量)及C-字符串常量。
字符串处理反例
反例一
#include <stdio.h>
void GETS(char *p)
{
printf("\nInput a string: ");
scanf("%s", p);
}
int main()
{
char *p1, *p2="Hello world!";
GETS(p1);
printf("%s\n", p1);
GETS(p2);
printf("%s\n", p2);
return 0;
}
这个程序是可以编译通过的,但是我们不难发现,p1指向不明,而p2指向不可写的常量区,当我们运行的时候就会无法输入。
那该怎么修改呢?
char p1[80], p2[80];
或者
char *p1, p2[80];
p1 = (char*)malloc(80);
// ……
free(p1);
反例二
#include <stdio.h>
int main()
{
unsigned long x=1234567890;
char p[5];
unsigned long y=4210356789;
gets(p);
// 输入字符串,可能破坏x
x = 1234567890;
//修改x的值可能影响超长的字符串
return 0;
}
这个程序同样没有错误,但是可靠性不高。
我们可以用课程提供的程序来验证一下。
串长<5时,无事发生。

串长<28时,同样无事发生。

串长=28时,不可思议的事情发生了,在修改了x的值后字符串变化了。

串长>28时,不可思议的事情发生了,x和字符串都遭到过破坏。

不过,我们同样可以发现,无论x和str怎么变化,y都不受影响。
我们可以用一张图来解释这一切:

可以看到,y作为后声明的变量占据了最外层的内存空间,str的大小和x的再赋值都影响不到y。
C-字符串处理常见错误
- 关于容器:
- 没有设置容器
- 容器位于常量区
- 容器的容量太小
- 关于串结束标志:
- 没有在适当的位置设置串结束标志
- 串结束标志被破坏
- 直接使用赋值运算符、关系运算符等
- 字符串拷贝 (应该使用strcpy函数)
- 字符串拼接 (应该使用strcat函数)
- 字符串比较 (应该使用strcmp函数)
课程任务
自定义函数实现C-字符串基本操作
C 语言中,对 C-字符串的操作体现在若干标准函数,如 strlen、strcpy、strncpy、strcat、strcmp、
atoi、atof、gets、puts、sprintf, sscanf 等。
本部分练习要求实现如下 5 个函数,函数原型已经给定:
unsigned int StrLen(const char *str); // 计算字符串的长度
char *StrCpy(char *dest, const char *source); // 字符串复制(拷贝)
char *StrCat(char *dest, const char *source); // 字符串拼接
int StrCmp(const char *str1, const char *str2); // 字符串比较(按 ASCII 序)
int AtoI(const char *str); // 将字符串转换成整数
StrLen
遍历一遍即可
unsigned int StrLen(const char *str)// 计算字符串的长度
{
unsigned int i;
for(i=0;str[i];i++);
return i;
}
StrCpy
同样遍历一遍
char *StrCpy(char *dest, const char *source) // 字符串复制(拷贝)
{
int i;
for(i=0;source[i];i++)
{
dest[i]=source[i];
}
dest[i]='\0';
return dest;
}
StrCat
这里可以用到前面的StrLen
char *StrCat(char *dest, const char *source) // 字符串拼接
{
int i;
unsigned int n;
n=StrLen(dest);
for(i=0;source[i];i++)
{
dest[n+i]=source[i];
}
return dest;
}
不过奇怪的是,我一开始使用dest[StrLen(dest)+i]=source[i];却无法实现,可能是类型转换的问题?
StrCmp
首先我们要知道作为原型的strcmp()是怎么一回事。
两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止。
感谢评论区同学的指正!
int StrCmp(const char *str1, const char *str2)// 字符串比较(按 ASCII 序)
{
int n;
while(!(n=*(unsigned char*)str1-*(unsigned char*)str2)&&*str2)
{
str1++;
str2++;
}
if(n==0)
return n;
n=(n<0)?-1:1;
return n;
}
AtoI
首先我们得明白atoi函数是做什么的。
C 库函数 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。
值得注意的是,诸如'4233ABCD'的字符串,atoi会将其转换为4233。
int AtoI(const char *str) // 将字符串转换成整数
{
int flag=1,s=0;
while (*str==' ')//跳过空白字符
str++;
if(*str=='-'||*str=='+')//判断正负
{
if(*str=='-')
flag=-1;
str++;
}
else if(*str<'0'||*str>'9')//若首字符不为数字或正负号返回0
return 0;
while(*str&&*str<='9'&&*str>='0')
{
s=s*10+*str-'0';
str++;
}
return s*flag;
}
好了,第一个任务就...完成了(心虚)

浙公网安备 33010602011771号