C语言|《C Primer Plus》读书笔记

字符串和字符串函数

字符串数组初始化:

\\定义字符串数组:

const char m1[40] = "Limit youtself to one line's worth.";

\\可以省略数组大小,让编译器自动计算数组大小:

const char m2[] = "Limit youtself to one line's worth.";

\\使用指针表示法创建字符串:

const char* pt1 = "Something is pointing at me.";

旧I/O函数:

gets() 读取整行输入,直到遇到换行符,然后丢弃换行符。

puts() 用于显示字符串,并在末尾添加换行符。

#include<stdio.h>
#define STLEN 81
int main(void)
{
    char words[STLEN];
    puts("Enter a string,Please.");
    gets(words);
    printf("Yout string twice:\n");
    printf("%s\n",words);
    puts(words);
    puts("Done.");
    return 0;
}

新I/O函数:

fgets()第1个参数为写入的字符数组名称。

fgets()函数通过第2个参数(例如n)限制读入的字符数来解决溢出问题。

fgets()将读取n-1个字符或遇到第一个换行符为止。fgets()读到的换行会存在字符串中。

fgets()第3个函数指明要读入的文件。如果用stdin 可表示从键盘输入,stdout表示从命令行输出。

gets_s()函数不需要第三个参数,但没fgets()方便

终极版本——s_gets函数,读取整行输出并用空字符代替换行符。(或者读取一部分输出,丢弃剩余一部分。

 自定义输入/输出函数:

一般可采用getchar() 和 putchar() 配合循环whlie(*str)来定制I/O函数。

//实现puts()函数
int put2(const char * string){
int count = 0;
while (*string){
putchar(*string++);//获取字符并将其保存到*(string+i)
count++;
}
putchar('\n');

return(count);//返回字符个数
}

字符串函数:

主要涉及四种字符串函数及其变种。

查询长度strlen()

//该函数可缩短字符串长度
void fit(char *string, unsigned int size){
    if (strlen(string) > size)
        string[size] = 0;
}    

拼接字符串strcat()

 strcat()接收两个字符串作为参数,把第二个字符串拼接在第一个字符串的末尾。

strncar()函数第三个参数指定了最大添加字符数,确保安全性(第一个字符串可能不够大来容纳第二个字符串)

strcat(str1,str2);

strncat(str1,str2,n);//n限制最大添加字符数

比较字符串strcmp()

 如果两个字符串参数相同,返回0,否则返回非零值。(非零值都为真)

常用测试条件:

while(strcmp(str1,str2)){
......
}

strncmp()第三个参数可限定查找的字符数:

 

复制字符串strcpy()

直接拷贝字符串是不可行的。

char ptr1[40];
char ptr2[40];

ptr1 = ptr2;//仅仅是把指针赋值

正确方法:

char ptr1[40];
char ptr2[40];

strcpy(ptr1.ptr2);//复制字符串2覆盖字符串1

strncpy(target, source, n)的第三个参数指明可拷贝的最大字符数

写入字符串sprintf()

sprintf(str1, "%s, %-19s", str2, str3);
printf("%s", str1);//将"%s, %-19s"写入str1

ctype.h 字符函数

while(*str){
*str = toupper(*str);//将str字符串全部大写
str++;
}

其他自搜可用。

命令行参数

main()后两个参数,需要在命令行下调用,不太会用。

实例应用:字符串排序

 

选择排序算法:

void stsrt(char *strings[], int num){    //采用排序指针而非字符串
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;    //交换两个字符串位置
}
}

存储类别,链接和内存管理

本章难度很大,不是很理解。

部分概念:

作用域

作用域有:块作用域,函数作用域,函数原型作用域或文件作用域。

块作用域:声明在语句块中的变量,在语句块内可见

函数作用域::声明在函数中的变量,函数体内可见

函数原型作用域:仅仅在函数原型的那个括号()里面可见。

文件作用域: 变量定义在函数的外面,从定义到文件末尾可见

链接

C变量有3种链接属性:外部链接、内部链接和无链接。块作用域、函数作用域和函数原型作用域的变量都是无链接变量。

具有文件作用域的变量可以时外部链接或内部链接,外部链接可在多文件程序中使用,内部链接只能在当前单元使用。

存储类别说明符static可区分内部链接和外部链接:

 int a = 6; //外部链接

static int b = 5; //内部链接 

static实例:函数调用计数。该代码避免了使用全局变量,提高安全性。

 1 #include <stdio.h>
 2 void count();
 3 int main(void)
 4 {
 5     int i=0;
 6     for (i = 0;i <= 5;i++)
 7     {
 8             count();
 9     }
10     return 0;
11 }
12 void count()
13 {
14     /*声明一个静态局部变量*/
15     static num = 0;
16     num++;
17     printf("%d\n",num);
18 }

存储期

存储期描述了对象的生存期。(不太懂)

C对象有4种存储期:静态存储期、线程存储期、自动存储期、动态分配存储期。

静态存储期: 静态存储期的对象在程序执行期间一直存在。文件作用域变量具有静态存储期。

线程存储期:用于并发程序设计,程序执行可分为多个线程。具有线程存储期的对象,从被声明至线程结束期间存在。

以关键字_Thread_local 声明一个对象时,每个线程都获得该变量的私有备份。

自动存储期:块作用域变量通常具有自动存储期。内存自动分配和释放。 块作用域变量在前面加上static可以变长静态存储期。

随机数及实例

rand()函数

#include <stdlib.h>  //前置库
#include <stdio.h> int main(){ srand(seed); //生成随机数种子 rand(); //生成随机数 }

实例:

生成1000个1-10的随机数,统计其出现次数并打印。

 1 #include <stdio.h>
 2 #include <time.h>
 3 #include <stdlib.h>
 4 #define LEN 11
 5 
 6 void show_array(int * a, int n);
 7 
 8 int main(void)
 9 {
10     int i, a[LEN];
11 
12      for (i = 0; i < LEN; i++)
13     {
14         a[i] = 0;
15     }
16     
17     for (int j = 0; j < 1000; j++){
18         srand(j*100+(unsigned int)time(0)); //生成1000个随机数
19         for (i = 1; i < LEN; i++)
20         {
21             if(rand()%10+1 == i)  //把1000个随机数放入桶中
22             a[i] +=1;
23         }
24     }
25     show_array(a, LEN);
26     return 0;
27 }
28 void show_array(int * a, int n){
29         for (int i = 1; i < LEN; i++)
30     {
31         printf("a[%d]:%d\n",i,a[i]);
32     }
33 }

malloc()函数和free()函数

malloc()分配内存,可用来创建数组。

free()释放内存

例1:要求输入元素个数及元素值,采用malloc()函数为其设置数组并赋值

#include <stdio.h>
#include <stdlib.h>

int *make_array(int elem, int val);
void show_array(const int ar[], int n);

int main(void)
{
    int *pa;
    int size;
    int value;

    printf("Enter the number of elements: ");
    while (scanf("%d", &size) == 1 && size > 0) //循环输入数组元素
    {
        printf("Enter the initialization value: ");
        scanf("%d", &value);
        pa = make_array(size, value);
        if (pa) 
        {
            show_array(pa, size);
            free(pa);
        }
        printf("Enter the number of elements (<1 to quit): ");
    }
    printf("Done.\n");

    return 0;
}
int *make_array(int elem, int val){  //使用malloc()创建数组
    int * ptr;
    ptr = (int *)malloc(elem * sizeof(int));
    for(int i = 0; i < elem; i++){
        *(ptr + i) = val;
    }
    return ptr;
}
void show_array(const int ar[], int n){ //展示数组
    int cnt = 0; 
    for(int i = 0; i < n; i++){
        printf("%d ",ar[i]);
        cnt++;
        if ((cnt + 1) % 8 == 0)
            printf("\n");
    }
    return;
}

输出结果:

Enter the number of elements: 3
Enter the initialization value: 2
2 2 2 Enter the number of elements (<1 to quit):

例2:要求输入指定数量(n)个单词,将其存放并逐词输出。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #define LEN 256
 5 
 6 int main(void)
 7 {
 8     char **pt; //指向指针的指针,即指向数个字符串的指针
 9     int i, n, length;
10     char temp[LEN];
11 
12     printf("How many words do you wish to enter? ");
13     scanf("%d", &n);
14     if ((pt = (char **)malloc(n * sizeof(char *))) != NULL)
15     {
16         printf("Enter %d words now:\n", n);
17         for (i = 0; i < n; i++)
18         {
19             scanf("%255s", temp);
20             length = strlen(temp) + 1;
21             pt[i] = (char *)malloc(length * sizeof(char));
22             //采用malloc()存放
23             if (NULL == pt[i])
24             {
25                 printf("Memory allocation failed!\n");
26                 exit(EXIT_FAILURE);
27             }
28             strcpy(pt[i], temp);
29             //将temp内容拷贝至pt[i]
30         }
31         printf("Here are your words:\n");
32         for (i = 0; i < n; i++)
33         {
34             puts(pt[i]);
35             free(pt[i]);
36             pt[i] = NULL;
37         }
38         free(pt);
39         pt = NULL;
40 //释放pt指向的内存后再释放pt为NULL指针
41     }
42     else
43     {
44         printf("Memory allocation failed!\n");
45         exit(EXIT_FAILURE);
46     }
47 
48     return 0;
49 }

输出结果:

How many words do you wish to enter? 3
Enter 3 words now:
hello world alion
Here are your words:
hello
world
alion

文件输入输出

fopen函数

该函数声明在stdio.h中,它的第一个参数是待打开文件的名称(确切的说是一个包含该文件名的字符串地址),第二个参数是一个字符串,指定待打开文件的模式:

程序成功打开文件后,fopen()将返回文件指针file pointer,其他I/O函数可以使用这个指针指向该文件。

getc()putc()函数

这两个函数与getchar()putchar()类似,但是要告诉这两个函数使用哪一个文件。

 1 int ch;           // 用int类型的变量EOF
 2 FILE * fp;
 3 fp = fopen("wacky.txt", "r");
 4 ch = getc(fp);    // 获取初始输入
 5 while (ch != EOF)
 6 {
 7     putchar(ch);  // 处理输入
 8     ch = getc(fp);// 获取下一个输入
 9 }
10 
11 // 简化一下
12 int ch;
13 FILE * fp;
14 fp = fopen("wacky.txt", "r");
15 while ((ch = getc(fp) != EOF)
16 {
17     putchar(ch);  // 处理输入
18 }

fclose()函数

fclose(fp)函数关闭fp指定的文件,必要时刷新缓冲区。对于较正式的程序,应该检查是否成功关闭文件。如果成功关闭,fclose()函数返回0,否则返回EOF。

if (fclose(fp) != 0)
    printf("Error in closeing file %s\n", argv[1]);//argv[I]表示文件名

指向标准文件的指针

随机访问:fseek()ftell()

有了fseek()函数,就可以把文件看成数组,在fopen()打开的文件中直接移动到任意字节处。

 1 /* reverse.c -- 倒序显示文件中的内容 */
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #define CNTL_Z '\032'   /* DOS文本文件中的文件结尾标记 */
 5 #define SLEN 81
 6 int main(void)
 7 {
 8     char file[SLEN];
 9     char ch;
10     FILE *fp;
11     long count, last;
12     
13     puts("Enter the name of the file to be processed:");
14     scanf("%80s", file);
15     if ((fp = fopen(file, "rb")) == NULL)
16     {
17         printf("reverse can't open %s\n", file);
18         exit(EXIR_FAILURE)
19     }
20     
21     fseek(fp, 0L, SEEK_END);      /* 定位到文件末尾 */
22     last = ftell(fp);
23     for (count = 1L; cout <= last; count++)
24     {
25         fseek(fp, -count, SEEK_END); /* 回退 */
26         ch = getc(fp);
27         if (ch != CNTL_Z && ch != '\r') /* MS-DOS文件 */
28             putchar(ch);
29     }
30     putchar('\n');
31     fclose(fp);
32     return 0;
33 }

fprintf()fscanf()函数

fprintf(stdout, "%s\n", "Succ");
while (fscanf(fp, "%s", words) == 1)
rewind(fp);  /* 返回到文件开始处 */
posted @ 2022-03-25 20:18  C₅H₁₂O₄季戊四醇  阅读(99)  评论(0)    收藏  举报