C-study(十一)

字符串

以空字符 ‘\0’ 结尾的char类型数组

函数传首字符地址指针,通过空字符确定结束

不同类型的0
空字符
‘\0’ 标记字符串结尾,对应字符编码是0,
整数类型,占1字节 eg:" " 占 2 字节 , ′ " 占2字节,' "2字节'占1字节

空指针
NULL,有一个值,不会和任何数据的有效地址对应
指针类型,占4字节,
通常用于返回有效地址表示特殊情况发生,
eg,遇到文件结尾或者未能按预期执行

#include <stdio.h>//puts
#define MSG "I'm special"
#define MAXLENGTH 81
	char words[MAXLENGTH] = "I am a string in an array.";
    const char *pt1 = "Something is pointing at me .";
    puts("Here are some strings :"); // 只显示字符串,且自动加上换行符
    puts(MSG);
    puts(words);
    puts(pt1);
    words[8] = 'p';
    puts(words);

定义

字符串常量 字符字面量

字符串双引号括起来的字符和(编译器自动加入末尾的)'\0’字符

作为可执行文件的一部分存储在数据段
载入程序时载入字符串
存储在静态存储区,只会被存储一次

char greeting[50] = "Hello,and"" how are"" you"
                    " today !";
/*即"Hello, and how are you today ! ";
字符串字面量之间没有间隔,或者空白字符分隔,等同于串联起来的字符串字面量*/
printf("\"Run,Spot,run !\" exclaimed Dick.\n");
/*如果要在字符串内部使用双引号,必须在双引号前面加上一个反斜杠(\)
 * 输出如下:"Run,Spot, run ! " exclaimed Dick.*/
printf("%s,%p, %c\n", "we", "are", *"space farers");
/*输出 we,0x100000f61,s
%p 打印字符串首字符的地址,双引号括起来的内容相当于指向该字符串存储位置的指针
%c *"space farers"表示字符串指向地址上存储的值,即首字符s */

字符串数组和指针

必须让编译器知道需要多少空间
字符数组有空间,有副本
字符指针只存字符串常量的地址

const char m1[40] = "one line's worth.";
/*const表明不会更改这个字符串、
数组元素个数至少比字符串长度多1('\0')、所有未被使用的元素都被自动初始化为'\0'
相当于const char m1[40] = {'o', 'n', 'e', ' ', 'l', 'i', 'n', 'e', '\'','s', ' ', 'w', 'o', 'r', 't', 'h', '.', '\0'};
有'\0'即为字符串,无'\0'即为字符数组
*/

const char m2[] = "If you can't think of anything, fake it.";
/*省略大小,编译器自动计算,查找末尾的空字符
 * 只可在初始化使用,稍后填充的数组,声明时必须指定大小*/

char cookies[1];// 有效
char cakes[2 + 5];// 有效,数组大小是整型常量表达式
char pies[2 * sizeof(long double) + 1]; // 有效
int n = 8;
char crunbs[n]; // 在C99标准之前无效,C99标准之后这种数组是变长数组

// 字符数组名和其他数组名一样,是该数组首元素的地址。
char car[10] = "Tata";
// car == &car[0];
// *car == 'T';
// *(car + 1) == car[1] == 'a';

char ar[] = MSG;
/* char ar[]="I'm special";
 * 开始运行时在内存中分配一个内含12(11+1'\0')个元素的数组,把字符串拷到数组中,每个元素被初始化为对应的字符
 * 字符串有两个副本,静态内存的字符串字面量,存储在ar1数组中的字符串
 * ar:数组首元素的别名,地址常量,不可以对ar赋值,指向别处无法访问该字符串,不可以++ --
 * 因为是拷贝,所以数组可以是const也可以不是const修饰
 *
 * ar[1]、*(ar + 1)、 不可以*(ar++);
 * ar = pt 指向别处无法访问该字符串
 * ar1[7] = 'M'、*(ar1 + 7) = 'M'、修改的是拷贝的副本,数组名是常量,数组元素是变量(除非const) */

const char *pt = MSG;
/* 指针表示法创建字符串,双引号内容决定预留空间
 * 运行时把字符串地址存储在指针变量,指向字符串首字符
 * 指针值可改变,可被赋值,++指向第二个字符,pt[1],*(pt+1),*(pt++),pt=ar
 * 因为是指向,字符串常量为const,pt1也应该是指向const的指针,不可以通过指针改变字符串,指针可以指向其他位置
 * 通过指针改变字符串常量会内存错误,pt[3]='F' 会导致所有引用MSG都变 */
printf("address of \"I'm special\": %p\n", "I'm special");
printf("address ar: %p\n", ar); // 拷贝一份到ar,两份地址不同
printf("address pt : %p\n", pt); // 和字符串位置相同,pt指向字符串首字符
printf("address of MSG: %p\n", MSG); // 只替换,地址相同
printf("address of \"I'm special\": %p\n", "I'm special"); 
// 多次使用的相同字面量存储在一处或多处,更改一处可能会影响所有使用该字符串的代码


const char *mesg = "Don't be a fool!";
const char *copy;
copy = mesg; // while(mesg==copy) 判断两个指针是否指向同一位置
printf("%s \n", copy);
printf("mesg = %s; &mesg = %p; value = %p\n", mesg, &mesg, mesg);
printf("copy = %s; &copy = %p; value = %p\n", copy, &copy, copy);
/* 输出
mesg = Don't be a fool!; &mesg = 0x0012ff48; value = 0x0040a000
copy = Don't be a fool!; &copy = 0x0012ff44; value = 0x0040a000
第二项:指针的地址,每个指针4字节
第三项:指针指向的地址,都指向同一个字符串,并未拷贝
*/

字符串二维数组

#define SLEN 40
#define LIM 5
 	const char *mytalents[LIM] = {
        "Adding numbers swiftly",
        "Multiplying accurately",
        "Stashing data",
        "Following instructions to the letter",
        "Understanding the C language"};
    /* 5个字符串
     * mytalents[0]表示第一个字符串
     * mytalents[1][2]表示第2个字符串的第3个字符
     * 内含5个指针的数组,在系统中占5*8=40字节
     * 字符串都被存在静态存储区,不可以通过指针修改字符串
     * 不规则数组,每个指针指向的字符串不必存储在连续的内存中
     * 效率高
     * */
    char yourtalents[LIM][SLEN] = {
        "Walking in a straight line",
        "Sleeping",
        "Watching television",
        "Mailing letters",
        "Reading email"};
    /* 内含5个数组的数组,每个数组内含40个char类型的值,共占用200字节
     * 数组存储字符串字面量的副本,可以更改内容,会为字符串预留空间
     * 规则数组,每个元素大小必须相同,是能储存最长字符串的大小
     */
    int i;
    puts("Let's compare talents. ");
    printf("%-36s %-25s\n", "My Talents", "Your Talents");
    for (i = 0; i < LIM; i++)
        printf("%-36s %-25s\n", mytalents[i], yourtalents[i]);
    printf("\nsizeof mytalents: %zd,sizeof yourtalents: %zd\n", sizeof(mytalents), sizeof(yourtalents));

在这里插入图片描述

输入

输入之前先分配空间

gets

超出长度擦写现有数据、不安全
换行符结束

#define STLEN 81
    char words[STLEN];
    puts("Enter a string, please.");
    gets(words);
    /*典型用法,整行除了\n,都读入
    不检测输入长度,输入过长导致缓冲区溢出,会擦写掉其他的数据,访问时会报分段错误 segmentation fault
    部分编译器(C99)会报 unsafe,C11不支持
    可以#define STLEN 5 尝试错误*/
    printf("Your string twice : \n");
    printf("%s \n", words);
    puts(words);
    puts("Done.");

fgets fputs

fgets:因为存换行符,通常和fputs配对

#define SALEN 14
    char words[SALEN];
    puts("Enter a string, please.");
    fgets(words, SALEN, stdin);
    /* 读入字符串存入words
     * 读入字符的最大数量SALEN,SALEN-1个字符(末尾加\0)或者到第一个换行符结束(存\n\0)
     * 读入的文件,从键盘stdin */
    printf("Your string twice(puts(),then fputs()):\n");
    puts(words); // puts会自动加上换行符,加上原本fgets的换行符
    fputs(words, stdout);
    /* fgets原本的换行符,不加多余换行
     * 从文件输出,屏幕输出stdout
     * 返回指向char的指针,返回地址与传入的第一个参数相同
     * 读到文件结尾就返回一个特殊的指针 空指针NULL 保证不会指向有效的数据*/
    puts("Done.");

    //原样打印输入
    while (fgets(words, SALEN, stdin) != NULL && words[0] != '\n')
    { /*读到的字符串不为空,且第一个字符不是换行符,一直输出
	  使用缓冲I/O,用户按下return之前,输入都在临时缓冲区,按下之后在输入中增加一个换行符,整行发给fgets
	  fputs输出把字符发送给另一个缓冲区,换行符之后发送至屏幕*/
        puts(words);
    }

    //取数组正确输入,不要\n
    int i; 
    puts("Enter strings (empty line to quit): ");
    while (fgets(words, SALEN, stdin) != NULL && words[0] != '\n')
    {
        i = 0;
        while (words[i] != '\n' && words[i] != '\0')
            // 遍历直到遇到换行或空格
            i++;
        if (words[i] == '\n') // 先遇到换行
            words[i] = '\0';  // 替换换行符
        else // 先遇到空格丢掉剩余部分,避免下次读取错误
            while (getchar() != '\n')
                // 读取但不储存输入,包括\n
                continue;
        puts(words);
        puts("done");
    }

在这里插入图片描述

gets_s

gets_s (words,STLEN);
只从标准输入中读数据
读到换行符丢弃
超过最大字符数:目标数组首字符设为空字符,读取并丢弃随后的输入直到换行符或文件结尾,然后返回空指针,调用依赖实现的处理函数或者选择的其他函数

s_gets

处理fgets 换行符问题

char *s_gets(char *st, int n)
{//读一行最多n个,去掉\n
    char *ret_val;
    int i = 0;
    ret_val = fgets(st, n, stdin);
    if (ret_val) // 即,ret_val != NULL
    {
        while (st[i] != '\n' && st[i] != '\0')
            i++;
        if (st[i] == '\n')
            st[i] = '\0'; // 替换换行
        else
            while (getchar() != '\n')
                continue;
        /*只读n-1个字符,空字符结尾,丢弃剩余
        避免留在缓冲区导致下一次读取错误*/
    }
    return ret_val;
}

scanf

获取单词
第一个非空白字符作为字符串开始
%s下一个空白字符作为字符串结束
%10s 读取10个字符或者到第一个空白字符
剩余字符留在缓冲器等待下一次读取
返回读取成功的项或者EOF(文件结尾)

数据行过长也会溢出,字段宽度可以防止溢出
典型用法:读取并转换混合数据类型为某种标准形式

char name1[11], name2[11];
int count;
printf("Please enter 2 names. \n");
count = scanf("%5s %10s", name1, name2);
printf("I read the %d names %s and %s.\n", count, name1, name2);

在这里插入图片描述

输出

puts

字符串地址作为参数传递
自动加换行符,和丢弃换行符的gets配对
遇到空字符 ‘\0’ 停止输出

/* put_out.c --使用puts () */
#define DEF "I am a #defined string . "
    char str1[80] = "An array was initialized to me.";
    const char *str2 = "A pointer was initialized to me.";
    puts("I'm an argument to puts().");
    puts(DEF);
    puts(str1);
    puts(str2);
    puts(&str1[5]); // 字符串第6个字符开始打印
    puts(str2 + 4); // 字符串第5个字符开始打印

    char side_a[] = "Side A";
    char dont[] = {'w', 'o', 'w', '!'};
    char side_b[] = "side B";
    puts(dont);
    /* dont不是一个字符串,缺少表示结束的空字符,
    puts不知道在何处停止,会一直打印后面内存的内容,直到遇见空字符*/

fputs

第二个参数指明要写入数据的文件,stdout
不会在输出末尾添加换行符,和保留换行符的fgets配对

char line [81] ;
while (gets(line) )//与while (gets (line)!= NULL)相同
	puts(line);//加换行

char line [81];
while (fgets (line,81,stdin) )//存换行
	fputs(line, stdout);

printf

字符串地址传参
格式化不同数据类型
需要指明换行符

printf("%s\n", string); // 相当于puts(string) ;
printf("well,%s,%s \n", name, MSG);

自定义输入输出函数

在getchar()和putchar()基础上自定义所需函数

int put2(const char *string); // 打印不要\n,记数

	put2("If I'd as much money");
    put2(" as I could spend, \n");
    printf("I count %d characters. \n", put2("I never would cry old chairs to mend."));
    
int put2(const char *string)
{/*不会改变字符串,使用const 
char sting[]:实参是数组,
char *string:实参可以是数组名,双引号字符串,char * 变量
一般传参不需要长度,以空字符结尾*/
    int count = 0;
    while (*string)
    { // *string!='\0' string[i]!='\0' 指向空字符值为0
        putchar(*string++);
        count++;
        /* *string++ 相当于 *(string++),输出*string ,string++递增指针指向下一个字符,相当于string[i++]
            ++*string,*string,H,然后++,G
        */
    }
    return count;
}

string.h

字符串处理函数

const char * s作为函数参数:该字符串不会被该函数更改
restrict :修饰限制

strlen

size_t strlen (const char * s) ;
返回s字符串中的字符数,不包括空字符

#include <string.h>/*内含宇符串函数原型*/
void fit (char *, unsigned int);

    char mesg[] = "Things should be as simple as possible,"
                  "but not simpler.";
    puts(mesg);
    fit(mesg, 38);
    puts(mesg); // 遇到空字符停止
    puts("Let 's look at some more of the string.");
    puts(mesg + 39); // 打印剩下的部分
    
void fit(char *string, unsigned int size)
{
    if (strlen(string) > size)
        string[size] = '\0'; // 超出部分替换为空字符 string[38]='\0'
}

在这里插入图片描述

strcat strncat

strcat
char *strcat(char * restrict s1,const char * restrict s2);
把s2的备份(包括空字符)附加在s1末尾,作为s1,不更改s2
s2的第一个字符覆盖s1的空字符
返回s1首地址

不检测长度,如果相加长度超过第一个字符串的长度则报错,错误可避免
可以用strlen(),计算长度并判断,拼接后的字符串长度加1 用于存放末尾的空字符

strncat
char *strncat(char *restrict s1,const char *restrict s2,size_t n);
n:指定最大添加字符数
最大长度或者空字符时停止,最后均会自动添加空字符

#define SIZE 30
#define BUGSIZE 13
char *s_gets(char *st, int n);

    char flower[SIZE];
    char addon[] = "s smell like old shoes. ";
    char bug[BUGSIZE];
    int available;
    puts("what is your favorite flower?");
    s_gets(flower, SIZE);
    if ((strlen(addon) + strlen(flower) + 1) <= SIZE)
        strcat(flower, addon);//相加长度超了会出错,先判断长度
    puts(flower);
    puts(addon);//strcat不影响第二个参数
    puts("what is your favorite bug?");
    s_gets(bug, BUGSIZE);
    available = BUGSIZE - strlen(bug) - 1;
    strncat(bug, addon, available);
    puts(bug);

strcmp strncmp

strcmp
int strcmp(const char * sl, const char s2) ;
比较两个字符串参数,相同返回0,否则返回非零值(ASCII值s1-s2)
即使数组长度不一样,只比较第一个空白字符前面的字符串
字符实际是整数类型,可以直接比较,不可作为strcmp的参数

strncmp
int strncmp(const char * s1,const char * s2, size_t n) ;
只比较前n个字符或者第一个空字符之前

#define ANSWER "Grant"
#define LIM_10 10
#define STOP "quit"
#define LISTSIZE 6

    char try[SIZE];
    puts("who is buried in Grant's tomb? ");
    s_gets(try, SIZE);
    // while (try !=ANSWER)//两个字符串地址是否相同
    while (strcmp(try, ANSWER) != 0)
    // 比较字符串内容 while(strcmp(try,ANSWER))
    {
        puts("No,that 's wrong. Try again.");
        s_gets(try, SIZE);
    }
    puts("That's right!");

    printf("strcmp (\"A\",\"A\") is %d\n", strcmp("A", "A"));
    printf("strcmp (\"A\",\"B\") is %d\n", strcmp("A", "B"));
    // ASCII排序ASTOP<B 则A-B<0 ASCII 差值为-1
    printf("strcmp (\"B\",\"A\") is %d\n", strcmp("B", "A"));
    // ASCII排序A<B 则B-A>0 ASCII 差值为1
    printf("strcmp (\"C\",\"A\") is %d\n", strcmp("C", "A"));
    // ASCII排序A<C 则C-A>0 ASCII 差值为2
    printf("strcmp (\"Z\", \"a\") is %d\n", strcmp("Z", "a"));
    // ASCII排序Z<a 则Z-a<0 ASCII 差值为-7  大写在小写前面
    printf("strcmp (\"apples\",\"apple\") is %d\n" ,strcmp("apples", "apple"));
    /*113 依次比较每个字符,直到发现第一对不同的字符为止,
    空字符在ASCII排第一最小*/

    char input[LIM_10][STLEN];
    int ct = 0;
    printf("Enter up to %d lines (type quit to quit):\n", LIM_10);
    while (ct < LIM_10 && s_gets(input[ct], STLEN) != NULL &&
           strcmp(input[ct], STOP) != 0)
        ct++;
    /*输入项达到LIM_10、读到EOF字符、输入quit时退出*/
    printf("%d strings entered\n", ct);   
    // while (ct < LIM_10 && s_gets(input[ct], STLEN) != NULL && input[ct][0] != '\0')
    //     /*输入项达到LIM_10、读到EOF字符、换行时退出
    //      *输入空行时,s_gets会把该行第一个字符(换行符)替换成空字符*/


    //strncmp
    const char *list[LISTSIZE] =
        {
            "astronomy", "astounding",
            "astrophysics", "ostracize",
            "asterism", "astrophobia"};
    int count = 0;
    int i;
    for (i = 0; i < LISTSIZE; i++)
        if (strncmp(list[i], "astro", 5) == 0) // 只比较前5个字符
        {
            printf("Found : %s \n", list[i]);
            count++;
        }
    printf("The list contained %d words beginning with astro. \n",count);

strcpy strncpy

strcpy
char *strcpy(char * restrict s1,const char * restrict s2);
拷贝整个s2(包括空字符)到s1,s2不变
必须在拷贝之前确认目标字符串有足够空间容纳源字符串的副本
s1:指向数据对象,并有足够空间;不必指向数组的开始,可以用于拷贝数组的一部分
s2:指针、数组名、字符串常量
返回s1的首地址

strncpy
char *strncpy(char *restrict s1, const char *restrict s2,size_t n);
n:可拷贝的最大字符数
拷贝s2的前n个字符(不拷贝空字符)或者空字符之前的字符(拷贝空字符)
一般把n设置为目标数组的长度-1,最后一个元素设置为空字符,确保拷贝前n个字符时存储的是一个字符串

#define TARGSIZE 7
#define WORDS "beast"

    char qwords[LIM][SLEN];
    char temp[SLEN];
    int i = 0;
    printf("Enter %d words beginning with q: \n", LIM);
    while (i < LIM && s_gets(temp, SLEN))
    {
        if (temp[0] != 'q')
            /*首字母不为q 时不存,不递增
            if (strncmp (temp, "q",1)!= 0)
            */
            printf("%s doesn't begin with q! \n", temp);
        else
        {     
            strcpy(qwords[i], temp);
            /*把temp的字符串拷贝到qwords[i]
            qwords[i]=temp 只拷贝地址,且语法错误
            temp="Solong";语法错误
            */
 			// strncpy(qwords[i], temp, TARGSIZE - 1);
            // qwords[i][TARGSIZE - 1] = '\0';//只拷6个,末尾+\0
            i++;
        }
    }
    puts("Here are the words accepted : ");
    for (i = 0; i < LIM; i++)
        puts(qwords[i]);

    const char *orig = WORDS;
    char copy[SLEN] = "Be the best that you can be . ";
    char *ps;
    puts(orig);
    puts(copy);
    ps = strcpy(copy + 7, orig);
    /*把orig拷贝到copy数组的第8个字符位置开始
    orig的空字符同样拷贝到copy,打印的时候遇到空字符结束
    返回第一个参数的值,第8个字符开始
    */
    puts(copy);
    puts(ps);

sprintf

stdio.h
把输入格式化为标准格式,写入字符串
第一个参数:目标字符串地址
其余参数和printf()相同:格式字符串,待写入项的列表

#define MAX 10
    char first[MAX];
    char last[MAX];
    char formal[2*MAX + 10];
    double prize;
    puts("Enter your first name : ");
    s_gets(first, MAX);
    puts("Enter your last name : ");
    s_gets(last, MAX);
    puts("Enter your prize money : ");
    scanf("%lf", &prize);
    sprintf(formal, "%s,%-19s: $%6.2f\n", last, first, prize);
    puts(formal);

memcpy memmove

void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
void *memmove(void *s1, const void *s2,size_t n);
/strcpy复制字符数组,memcpy和memmove复制任意类型的数组
s2指向的位置拷贝n字节到s1指向的位置,返回s1,restrict修饰说明不能有重叠区域
/

#define SIZE_10 10
void show_array(const int ar[], int n); // 如果编译器不支持C11的 ,可以注释掉下面这行
_Static_assert(sizeof(double) == 2 * sizeof(int), "double not twice int size");
//断言,编译器检查double不等于2倍int大小时,编译不通过并报错

   // mems.c--使用memcpy()和memmove()
    int values[SIZE_10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int target[SIZE_10];
    double curious[SIZE_10 / 2] = {2.0, 2.0e5, 2.0e10, 2.0e20, 5.0e30};

    puts("memcpy() used:");
    puts("values (original data):");
    show_array(values, SIZE_10);

    memcpy(target, values, SIZE_10 * sizeof(int));
    puts("target (copy of values):");
    show_array(target, SIZE_10);

    puts("\nUsing memmove()with overlapping ranges:");
    memmove(values + 2, values, 5 * sizeof(int));
    puts("values--elements 0-4 copied to 2-6:");
    show_array(values, SIZE_10);

    puts("\nUsing memcpy()to copy double to int:");
    memcpy(target, curious, (SIZE_10 / 2) * sizeof(double)); 
    /* 从curious拷贝5个double大小的数据到target 只负责拷贝不关心数据类型,不会做类型转换*/
    puts("target--5 doubles into 10 int positions:");
    show_array(target, SIZE_10 / 2);
    show_array(target + 5, SIZE_10 / 2);
    
void show_array(const int ar[], int n)
{
    int i;
    for (i = 0; i < n; i++)
        printf("%d ", ar[i]);
    putchar('\n');
}

其他

char *strchr (const char * s, int c) ;
如果s字符串中包含c字符,该函数返回指向s字符串首位置的指针(末尾的空字符也是字符串的一部分,所以在查找范围内);
如果在字符串s中未找到c字符,该函数则返回空指针。

char *strrchr(const char * s, int c);
该函数返回s字符串中c字符的最后一次出现的位置(末尾的空字符也是字符串的一部分,所以在查找范围内)。
如果未找到c字符,则返回空指针。

char *strpbrk (const char * s1,const char * s2);
如果s1字符中包含s2字符串中的任意字符,该函数返回指向s1字符串首位置的指针;
如果在s1字符串中未找到任何s2字符串中的字符,则返回空字符。

char *strstr (const char * sl,const char * s2) ;
该函数返回指向s1字符串中s2字符串出现首位置。如果在s1中没有找到s2,则返回空指针。

字符串排序

#define LIM_20 20  /*可读入的最多行数*/
#define HALT "" /*空字符串停止输入*/

void stsrt(char *strings[], int num); /*字符串排序函数*/

    char input[LIM_20][STLEN]; // STLEN 限制字符串长度,包括\0
    /*储存输入的数组,可存20个内含80个字符的字符串*/
    char *ptstr[LIM_20];
    /*指针数组,可存放20个指针,每个指针指向字符串首地址
    只比较首字母
    */
    int ct = 0; /*输入计数*/
    int k;      /*输出计数*/
    printf("Input up to %d lines,and I will sort them.\n", LIM_20);
    printf("To stop, press the Enter key at a line's start.\n");
    while (ct < LIM_20 && s_gets(input[ct], STLEN) != NULL && input[ct][0] != '\0')
    {
        ptstr[ct] = input[ct]; /*指针指向字符串首字符*/
        ct++;
        }
	stsrt (ptstr,ct) ;/*字符串排序函数,指针交换,并不修改input*/
    puts("\nHere's the sorted list : \n");
    for (k = 0; k < ct; k++)
        puts(ptstr[k]);
    /*排序后的指针*/

/*字符串-指针-排序函数*/
void stsrt(char *strings[], int num)
{ /*选择排序,每次循环和首元素比较,挑出最小的排在最前
    for n=首元素至n=倒数第2个元素
    {//找出剩余元素中的最小值,并将其放在第n个元素中
        for m第n+1个元素至最后一个元素,
            比较第m个元素与第n个元素,如果第m个元素更小,交换这两个元素的值
    }*/
    char *temp;
    int top, seek;
    for (top = 0; top < num - 1; top++)
        for (seek = top + 1; seek < num; seek++)
            if (strcmp(strings[top], strings[seek]) > 0)
            {
                temp = strings[top];
                strings[top] = strings[seek];
                strings[seek] = temp;
            }
}

在这里插入图片描述

ctype.h

字符处理函数
在这里插入图片描述

#include <string.h> //strchr
#include <ctype.h> //toupper ispunct
void ToUpper(char *str);
int PunctCount(const char *str);

   	char line[STLEN];
    char *find;
    puts("Please enter a line : ");
    fgets(line, STLEN, stdin);
    find = strchr(line, '\n'); // 查找换行符
    if (find)// 如果地址不是NULL,
        *find = '\0'; // 用空字符替换
    ToUpper(line);
    puts(line);
    printf("That line has %d punctuation characters.\n", PunctCount(line));
    
void ToUpper(char *str)
{
    while (*str)
    {// 遇到空字符停止 while(islower(*str)) 是小写返回真
        *str = toupper(*str); // 字符转换为大写,
        str++;
    }
}
int PunctCount(const char *str)
{
    int ct = 0;
    while (*str)
    {
        if (ispunct(*str)) // 统计标点符号个数
            ct++;
        str++;
    }
    return ct;
}

命令行参数

命令行:在命令行环境中,为运行程序输入命令的行
命令行参数是同一行的附加项,用于传参

不同集成环境输入参数方式不同
双引号括起来的多个单词为一个参数

#include <stdio.h> 
int main(int argc, char *argv[]) 
{/*编译为可执行文件repeat 调用: repeat Resistance is futile
argc :参数(命令行单词)数量 ,4
argv:字符串参数列表,参数从1开始存(大部分系统),每个指针指向字符串开始*/
    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]); // argv[0]指向repeat
    printf("\n");
	return 0 ;
}

在这里插入图片描述

字符串转数字

数字可以以字符串形式存储,以数值形式存储
数值形式用做数值运算,字符串形式用做屏幕显示
printf scanf
命令行参数被读取为字符串,转换为数字

#include <stdio.h>
#include <stdlib.h> //atoi atof(转换为浮点数) atof(转换为long)
#define LIM 30

// long strtol(const char *restrict nptr, char *restrict endptr, int base);
// /*指向待转换字符串的指针,标识数字后字符的地址,进制,字符串转化为long
// strtoul 字符串转化为unsigned long
// strtod 字符串转化为double*/

int main(int argc, char *argv[]) 
{
	//atoi转换,编译为hello,调用:hello 3
    int i, times;
    if (argc < 2 || (times = atoi(argv[1])) < 1)
        /*只有命令没有参数、或者参数转化为整数<1
        短路或,第一个条件成立才判断第二个
        atoi 把字符串开头的整数转换为整数,没有整数返回0*/
        printf("Usage : %s positive-number\n", argv[0]);
    else
        for (i = 0; i < times; i++)
            puts("Hello, good looking!");

	//strtol转换
	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); /*十进制转化number里的数字,数字返回给value,数字后的字符地址赋值给end*/
        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 ! \n");
    }
	return 0;
}

在这里插入图片描述

weixin073智慧旅游平台开发微信小程序+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
python017基于Python贫困生资助管理系统带vue前后端分离毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
weixin102旅游社交微信小程序+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值