计算机程序设计实训记录(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-字符串处理常见错误

  1. 关于容器:
    • 没有设置容器
    • 容器位于常量区
    • 容器的容量太小
  2. 关于串结束标志:
    • 没有在适当的位置设置串结束标志
    • 串结束标志被破坏
  3. 直接使用赋值运算符、关系运算符等
    • 字符串拷贝 (应该使用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;
}

好了,第一个任务就...完成了(心虚)

posted @ 2020-08-05 00:45  DoRCL  阅读(391)  评论(3)    收藏  举报