C语言day11 字符串及其函数(二)

用strcpy替换数组的一部分

#include <stdio.h>
#include <string.h>
#define WORDS "beast"

int main()
{
    char *orig = WORDS;
    char copy[40] = "Be the best that you can be.";

    puts(orig);
    puts(copy);
    strcpy(copy + 7, WORDS);
    puts(copy);

    return 0;
}
beast
Be the best that you can be.
Be the beast

strncpy(更安全)

strcpy 和strcat 都有一个安全漏洞
在这里插入图片描述
之前用strcpy做的示例程序里,目标数组很大可以容纳源字符串,所以没出错,我把目标数组改小

#include <stdio.h>
#include <string.h>
#define SIZE 40
#define LIM 5
char *s_gets(char *st, int n);
int main()
{
    char temp[SIZE];
    char target[LIM][LIM];
    int i=0;
    printf("Enter %d words beginning with q:\n", LIM);
    while(i<LIM && s_gets(temp, SIZE)!= NULL)//一定要把i<LIM放在前面,这样第五个q开头的单词输入后就直接退出了,用短路运算符时一定把首要判断条件放在前面,顺序是需要考虑一下的哦
    {
        if(temp[0]!='q')// 等效于if(strncmp(temp, "q", 1))
        {
            puts("This word is not beginning with q!");
        }
        else
        {
            if(i!=4)
                puts("Got one! Keep entering:");
            strcpy(target[i], temp);
            i++;
        }

    }
    printf("End of entering. The input words beginning with q:\n");
    for(i=0;i<LIM;i++)
        puts(target[i]);
    return 0;
}char *s_gets(char *st, int n)
{
    char *ret_val;
    int i=0;
    ret_val = fgets(st, n, stdin);
    if(ret_val)
    {
        while(*(st+i)!='\n' && st[i]!='\0')
            i++;
        if(st[i]=='\n')
            st[i] = '\0';
        else
            while(getchar()!='\n')
                continue;
    }
    return ret_val;
}

输出呈现这种错误,这是因为:
输入question太长了,临时数组长度为40,存的下,但是复制给目标数组时,目标数组长度只有5,所以只复制了前5个字符,没有复制到空字符,第二个quarter又是如此····
输出时,puts没有遇到空字符,就无法正确识别字符串结尾,于是输出了第一次遇到空字符前的所有字符,第二次输入也是如此,只是开始的位置变成了数组第二个元素的地址

Enter 5 words beginning with q:
question
Got one! Keep entering:
quarter
Got one! Keep entering:
quality
Got one! Keep entering:
queen
Got one! Keep entering:
query
End of entering. The input words beginning with q:
questquartqualiqueenquery
quartqualiqueenquery
qualiqueenquery
queenquery
query

用strncpy

if(i!=4)
	puts("Got one! Keep entering:");
strncpy(target[i], temp, LIM-1);
target[i][LIM-1]='\0';
Enter 5 words beginning with q:
quarter
Got one! Keep entering:
quality
Got one! Keep entering:
question
Got one! Keep entering:
queen
Got one! Keep entering:
quote
End of entering. The input words beginning with q:
quar
qual
ques
quee
quot

sprintf

sprint 把数据写入字符串,多以可以把很多项(包括数字和字符串)合并为字符串
printf写入屏幕
sprintf第一个参数是目标字符串的地址,其余参数和printf相同,也是格式字符串和待写入项列表

#include <stdio.h>
#include <string.h>
#define MAX 10
char *s_gets(char *st, int n);
int main()
{
    char first[MAX], last[MAX], all[MAX*2+20];
    double prize;

    puts("Enter your first name:");
    s_gets(first, MAX);
    puts("Enter your last name:");
    s_gets(last, MAX);
    puts("Enter your prize:");
    scanf("%lf", &prize);//注意scanf输入double用%lf,输出double用%f
    sprintf(all, "%s %s $%.2f\n", last, first, prize);
    puts(all);
    return 0;
}
char *s_gets(char *st, int n)
{
    char *ret_val;
    int i=0;
    ret_val = fgets(st, n, stdin);
    if(ret_val)
    {
        while(*(st+i)!='\n' && st[i]!='\0')
            i++;
        if(st[i]=='\n')
            st[i] = '\0';
        else
            while(getchar()!='\n')
                continue;
    }
    return ret_val;
}
Enter your first name:
galler
Enter your last name:
mary
Enter your prize:
1000
mary galler $1000.00

字符串函数总结

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

示例 字符串排序 strcm 选择排序算法 交换指针!!!

这个程序的巧妙之处是它通过交换指针实现排序

#include <stdio.h>
#include <string.h>
#define LIM 10
#define SIZE 40
char *s_gets(char *st, int n);
//void st_sort(char st[][SIZE], int n);
void st_sort(char *st[], int n);//指针数组的形式表示字符串数组
int main()
{
    unsigned int ct=0;
    unsigned int i;
    char *ptr;
    char st[LIM][SIZE];//字符串数组就是二维数组
    char *ptstr[LIM];//[]优先级高于*,ptstr先和[]结合,所以ptstr是一个数组,
    //又和前面的*结合,成为指针数组,即元素是指针

    printf("Please enter up to %d lines, and I will sort them.\n", LIM);
    puts("Press the enter key to stop.");
    //最首要的判定条件放在最前面,即ct<LIM
    //s_gets会把换行符替换为空字符,所以如果不输满LIM个字符,按下换行符就退出
    while(ct<LIM && (ptr=s_gets(st[ct], SIZE))!=NULL && st[ct][0]!='\0')
    {
        ptstr[ct] = st[ct];//把每个输入的字符串的地址存在指针数组中
        ct++;
    }
    st_sort(ptstr, ct);
    //输出排序后的字符串
    puts("The sorted strings:");
    for(i=0;i<ct;i++)
        puts(ptstr[i]);
    return 0;
}
char *s_gets(char *st, int n)
{
    char *ret_val;
    int i=0;
    ret_val = fgets(st, n, stdin);
    if(ret_val)
    {
        while(*(st+i)!='\n' && st[i]!='\0')
            i++;
        if(st[i]=='\n')
            st[i] = '\0';
        else
            while(getchar()!='\n')
                continue;
    }
    return ret_val;
}

//void st_sort(char st[][SIZE], int n)//数组法表示形参
void st_sort(char *st[], int n)
{
    unsigned int top, seek;
    char *temp;
    for(top=0;top<n-1;top++)
    {
        for(seek=top+1;seek<n;seek++)
        {
            if(strcmp(st[top], st[seek])>0)//大于0则st[top]应排在st[seek]后面
            {
                temp = st[top];
                //交换指针!!!
                st[top] = st[seek];//如果用数组法表示形参,这句代码错误,数组和数组不可直接赋值,但是指针形参使得编译器认为他们都是指针,可以赋值
                st[seek] = temp;
            }
        }
    }
}

可以看到,strcmp的返回值的正负性特别有用,使得我们的字符串排序变得极其轻松

不过,写程序时,我发现自己的问题:

  • 写关系表达式易错,本题是按下换行符则停止输入,我之前写成st[ct][0]==’\0’,结果程序不进去循环,我调试发现前两个表达式都没问题才发现自己写错了。易错
  • 排序算法中由于交换值会涉及到数组和数组之间的赋值,这在数组的使用规定中是不允许的,所以必须用指针法表示形参
  • 函数原型和函数定义的形参形式要一致,要么都是数组法,要么就都是指针法,不可混用,否则无法通过编译,报错
Please enter up to 10 lines, and I will sort them.
Press the enter key to stop.
fdfk
uio
op
ih
oa
sdfg

The sorted strings:
fdfk
ih
oa
op
sdfg
uio

选择排序

这个排序算法我在草稿纸上推了,很简单,比如10个数字要从小到大排序:
3 6 1 2 7 0 9 4 8 5
首先top=0,st[top]=3,seek从1开始向右遍历,当seek=2时st[seek]更小,于是交换
1 6 3 2 7 0 9 4 8 5
top还是0,seek=3,直到seek=5再次达到交换条件
0 6 3 2 7 1 9 4 8 5
······
所以第一次内层循环最多交换n-1次
而第二次内层循环,top=1,则最多交换n-2次
top=n-2时,最多交换一次
(top取值范围:0—n-2,seek取值范围:top+1—n-1)

所以最多交换次数:
1 + 2 + 3 + ⋯ + n − 1 = n ( n − 1 ) 2 1+2+3+\cdots+n-1=\frac{n(n-1)}{2} 1+2+3++n1=2n(n1)
在这里插入图片描述

示例 计算标点符号个数(用到ctype.h中的函数)

toupper

ispunct是ctype.h中的函数
在这里插入图片描述

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define LIMIT 101
void ToUpper(char *st);
unsigned int PunctCount(const char *);

int main()
{
    char line[LIMIT];
    char *find;

    puts("enter a line.");
    fgets(line, LIMIT, stdin);
    find = strchr(line, '\n');//查找换行符,如果找到了,就返回换行符的地址,否则返回空指针
    if(find)//空指针的值是0
        *find = '\0';//用空字符替换换行符
    ToUpper(line);
    puts(line);
    printf("That line has %u punctuation characters.\n", PunctCount(line));
    return 0;
}

void ToUpper(char *st)
{
    while(*st)//不是空字符则进入循环
    {*st = toupper(*st);
    st++;}
}

unsigned int PunctCount(const char *st)
{
    unsigned int n=0;
    while(*st)
    {
        if(ispunct(*st))
            n++;
        st++;
    }
    return n;
}

这个程序值得学习的地方是while(*st)和if(find),利用了空字符的指针的值是0

enter a line.
I'm trying to calculate the number of punctuation characters, and can you hele me?
I'M TRYING TO CALCULATE THE NUMBER OF PUNCTUATION CHARACTERS, AND CAN YOU HELE ME?
That line has 3 punctuation characters.

如果#define LIMIT 81则

enter a line.
I'm trying to calculate the number of punctuation characters, and can you hele me?
I'M TRYING TO CALCULATE THE NUMBER OF PUNCTUATION CHARACTERS, AND CAN YOU HELE M
That line has 2 punctuation characters.

给main函数带参数

示例1 输出参数和参数的个数

这个示例是在命令行执行,输出参数的个数和参数

参数的个数是操作系统检测到后赋给main的参数argc的(c是count的缩写),OS还把所有参数都赋给了main的指针数组参数,即把所有参数的地址发给了main函数

#include <stdio.h>
int main(int argc, char *argv[])
{
    int count;

    printf("The command line has %d arguments:\n", argc-1);
    for(count=1;count<argc;count++)
        printf("%d: %s\n", count, argv[count]);
    printf("\n");

    return 0;
}

直接在编译器中执行,不行,因为无法输入参数

The command line has 0 arguments:


Process returned 0 (0x0)   execution time : 0.597 s
Press any key to continue.

在命令行执行,可以输入参数

C:\Users\wulimmya>cd C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug

C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug>MyC Resistance is futile
The command line has 3 arguments:
1: Resistance
2: is
3: futile

在这里插入图片描述在这里插入图片描述

示例2 把命令行参数字符串转换为数字

这里说的是把键盘输入的数字,实际是一个个字符组成的字符串,把他们转换为数值形式,才可以用于程序的计算
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    int i, times;

    if(argc<2 || (times=atoi(argv[1]))<1)
        printf("Usage: %s positive-number\n", argv[0]);
    else
        for(i=0;i<times;i++)
            puts("Hello, good looking!");
    return 0;
}

atoi函数把字符串转换为int类型的整数

C:\Users\wulimmya>cd C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug

C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug>MyC 3
Hello, good looking!
Hello, good looking!
Hello, good looking!

C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug>MyC 1
Hello, good looking!

C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug>MyC
Usage: MyC positive-number

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#define LIM 30
char *s_gets(char *st, int n);
int main()
{
    char number[LIM];
    char *end;
    long value;

    puts("Enter a number (empty line to quit):");
    while(s_gets(number, LIM) && number[0]!='\0')
    {
        value = strtol(number, &end, 10);
        printf("base 10 input, base 10 output:%ld, stopped at %s (%d)\n",
               value, end, *end);

        value = strtol(number, &end, 16);
        printf("base 16 input, base 10 output: %ld, stopped at %s (%d)\n",
              value, end, *end);
        puts("Next number:");

    }
    puts("Bye!");
    return 0;
}

char *s_gets(char *st, int n)
{
    char *ret_val;
    int i=0;
    ret_val = fgets(st, n, stdin);
    if(ret_val)
    {
        while(*(st+i)!='\n' && st[i]!='\0')
            i++;
        if(st[i]=='\n')
            st[i] = '\0';
        else
            while(getchar()!='\n')
                continue;
    }
    return ret_val;
}
Enter a number (empty line to quit):
4
base 10 input, base 10 output:4, stopped at  (0)
base 16 input, base 10 output: 4, stopped at  (0)
Next number:
45
base 10 input, base 10 output:45, stopped at  (0)
base 16 input, base 10 output: 69, stopped at  (0)
Next number:
10atom
base 10 input, base 10 output:10, stopped at atom (97)
base 16 input, base 10 output: 266, stopped at tom (116)
Next number:

在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值