C和指针---读书小记

大大小小做过不少比赛项目,一直没时间总结到博客上,这两天看到任玉刚大佬写的博客,看来从小白进阶需要善于总结,遂决定开始写博客记录下平时的学习新的和经验。

最近在看《C和指针》,复习基础也很重要,开篇文章记录下要点方便以后复习。

1.条件操作符

例如:

a>5?b-6:c/2

可以读作“a是不是大于5?如果是就执行b-6,否则执行c/2

在什么场合使用比较好呢

例如:

if(a>5)

  b[2*c+d(e/5)]=3;

else

   b[2*c+d(e/5)]=20;

这里改用条件操作符就很方便

b[[2*c+d(e/5)]=a>5?3:20

2.计算字符串长度

虽然库里面已经有了,但是自己可以编写一个学习一下

int strlen(char *string)

{

int length=0;

/* 依次访问字符串内容,计算字符数,直到遇见NUL终止符*/

 while(*string++!='\0'

      length+=1;

   return  length;

}

3.递归问题

例如:需要将一个整数转换成可以打印的字符形式,一般采用的策略就是反复除以10,并打印余数,但是转换成字符有个简便的方式

‘0’+0=’0’;

‘0’+1=’1’;

‘0’+2=’2’;

这样余数加上‘0’就可以转化了,但是输出的值是反着的,故可用递归的思想解决

void binary2ascii(unsigned int value)

{

unsigned int quo;

quo=value/10;

if(quo!=0)

   binary2ascii(quo);

putchar(value%10+'0');

}

4.字符数组的初始化

按照一般的理解,你可能会认为字符数组的初始化是这样

char message [] ={‘H’,’e’,’l’,’l’,’o’,0};

这个方法看起来很笨拙,有更高端的写法

char message[]=”Hello”;

尽管看起来像字符串,实际上不是以下才是初始化字符串

char *message=”Hello”;

5.作为函数参数的多维数组

int matrix[3][10]

func2(marix)

/有以下两种方法声明函数/

void func2(int (*mat)[10] );

void func2(int mat[ ][ ]);

另外值得注意的是,多维数组的存储顺序是根据最右边的下标优先变化的原则确定。

6.关于字符串查找

6.1查找一个字符

在一个字符串中查找一个字符最简单的方法是使用strchrstrrchr函数,函数原型如下


char *strchr(char const *str,int ch);

char *strrchr(char const *str,int ch);

注意第二个参数是个整型值,strchr在字符串str中ch第一次出现的位置,找到后函数返回一个指向更改位置的指针。如果该字符并不存在与字符串中,函数就返回一个NULL指针。str函数功能与其类似,只是它返回的是该字符串中该字符最后出现的位置。例如:


char string[20]="Hello there";

char *check;



check=strchr(string,'h');

check所指向的位置是string+7,因为第一个h出现在这个位置,注意此处大小写是有区别的。

6.2查找人和几个字符串

strpbrk是个更为常见的函数,它并不是查找某个特定的字符串,而是查找任何一组字符第一次在字符串中出现的位置,它的原型如下:


char *strpbrk(char const *str ,cahr const *group);


这个函数返回一个指向str 中第一个匹配group中任何一个字符的字符位置,如果未找到匹配,函数返回一个NULL指针。例如:


char string[20]="Hello there";

char *check;



check=strpbrk(string , "aeiou");

check所指向的位置是string+1,因为这个位置是第二个参数中字符第一次出现的的位置,和上一个一样,也是区分大小写。

7.字符分类函数

以下函数如果参数满足条件就返回真(包含在ctype.h)


1.isspace       --------空白字符:空格,换页,换行,回车等等

2.isdigit       --------十进制数0-9

3.islower       --------小写字母a~z

4.isupper       --------大写字母A~Z

5.isalpha       --------字母a~z或者字母A~Z

6.ispunct       --------标点符号

例如:


if(ch>'A' && ch<'Z')  这条语句只能在ASCII机器上运行



可用以下语句替换则无论那个机器都能使用

if(isupper(ch))

8.关于结构体

声明结构体时可使用的一种良好技巧是用typedef创建一种新的类型,例如:


typedef struct{

    int a;

    char b;

    float c;

}Simple;

...

Simple x;

Simple y[20],*z;

9.函数指针

简单声明一个函数指针并不意味马上可以使用,访问前必须初始化指向某个函数,例如:

int fun( int )

int (*pf)(int) =&fun;

//之后我们就可以这样使用
int ans;
ans =f(25);
ans =(*pf)(25);
ans =pf(25);
9.1回调函数

例如,你需要编写函数比较整数大小,但同时需要用于其他字符串的比较,解决方案就是使用函数指针,你只需要编写一个函数,用于比较两个值,然后把一个指向这个函数的指针作为参数传递给查找函数,然后查找函数来执行值的比较,使用这种方法任何类型都可以进行比较。
注意:我们必须想函数传递指针而不是这个值本身,函数有个*void 形参,用于接收这个参数,然后指向这个值的指针便传递给比较函数。
使用这种技巧的函数被称为“回调函数”,因为用户把一个函数指针作为参数传递给其他函数,后者将“回调”用户的函数。(由于不知道进行比较的值,一般把参数类型声明为*void,表示“一个指向未知类型的指针”。例如下面的比较函数,它用于在链表中进行查找:

int compare(void const *a ,void const *b)
{
            if(*(int *)a ==*(int *)b )
            return 0;
            else
            return 1;
}
//这个函数将这样使用
Node *search_list(Node*node,void const *value,int (*compare)(void const*,void ocnst *));
....
abc= search_list(root,&value,compare);

注意:强制类型转换:比较函数的形参必须声明为void*以匹配查找函数的原型,然后在强制类型转换为int*类型,用于比较整数。
如果你希望在字符串列表中查找,则可这样写:

#include <string.h>
abc=search_list(root,&value,strcmp);

10.命令行参数

大家都知道C程序main函数具有两个形参,第一个通常是argc,它表示的命令行参数的数目,第二个是argv,它指向这组参数值(数组)的第一个元素。如果程序需要访问命令行参数,需要在main函数声明时加上这些参数。

int main(int argc,char **argv)
/*这两个参数的命名无所谓

假设命令行如下:

$ cc -c -o main.c insert.c -o test

下面灵魂画师上线。。。
1.png

11.字符串常量

看下面的语句

"xyz"+1

他似乎是个垃圾,这货居然试图在字符串上面进行某种加法运算。但实际上它是指针值加一,结果仍然是个指针,指向字符串中第二个字符:y
所以

*"xyz"          --1
"xyz"[2]        --2

这个式子1结果就是x 。注意结果不是整个字符串,只是第一个字符。
式子2结果就是字符z 。
上面曾经有将二进制转换成字符并且打印出来,现在改成16进制形式打印出来怎么做呢?
可以这样:

remainder =value %16;
if(remainder<10)
        putchar(remainder+'0');
else 
        putchar(remainder-10+'A');

另将二进制数转换成字符还有种骚操作

putchar("0123456789ABCDEF"[value%16]);

12.条件编译

下面显示了基本的条件编译形式

#if constant
        statement
#endif

此时若constant非零(真)那么statement就被正常编译,否则不执行。

#if constant
        statement
#elif constant1
        other statement
#else constant2
        others
#endif

13.输入输出函数

13.1错误报告

perror是一种简单的方式进行报告错误
它的原型定义于stdio.h

void perror(char const *message);

如果message 不是Null并且指向一个非空的字符串,perror就会打印出这个字符串,后面跟一个分号和空格,然后打印出一条用于解释该错误的信息。

13.2打开流

应该注意的是应该时刻检查fopen函数的返回值!如果函数失败,他会返回一个NULL值,如果程序不检查错误,这个NULL函数就会传给后续的I/O函数。

FILE *input 
input =fopen ("data3","r");
if(input ==NULL)
{
        perror("data");
        exit(EXIT_FALLURE);
}
13.3printf家族

这个家族共有三个函数:fprintf,printf,sprintf;

int fprintf(FILE*stream,char const *format,...);
int printf(char const *format,....);
int sprintf(char *buf ,char const *format);

使用printf,结果输出送到标准输出;
使用fprintf,你可以使用任何输出流;
而sprintf把他的结果作为一个NUL结尾的字符串存储到指定的buf缓冲区而不是写入流中。(这种方式在嵌入式开发中经常用到)。
注意:sprintf缓冲区的大小并未给定,可能会溢出,故应声明一个足够大的缓冲区。

14.标准库函数

标准库函数是个很好的工具箱,有很多实用工具我们未曾注意,下面将进行简单汇总

14.1 算术 ‘stdlib.h’
int abs(int value)

abs函数返回他的参数的绝对值

div_t div(int num,int den);

div函数把他的第2个参数除以第1个参数,产生商和余数,用一个div_t结构返回,这个结构包含两个字段

int quot;  //商
int rem ;  //余数
14.2随机数’stdlib.h’
int rand(void);
void srand(unsigned int seed);

一般使用时,使用每天的时间作为随机数产生的种子,例如

srand((unsigned int)time(NULL));
...
sth =rand()%i;
14.3字符串转换’stdlib.h’
int atoi(char const *string);                                   ---1
long int strtol(char const *string,char **unused ,int base);    ---2

第一个函数把字符转换成整数
第二个函数如果第二个参数非NULL,则保存在第二个参数所指向的位置

14.4浮点表示’math.h’
double modf(double value ,double *ipart);

该函数把一个浮点值分成整数和小数部分,每个部分都具有和原值一样的符号,整数部分以double类型存储与第二个参数所指向的内存位置,小数部分作为函数的返回值。

14.5幂级数’math.h’
double pow (double x,double y);
double sqrt(double x);

pow函数返回X的Y次方的值,由于计算中可能遇到对数,所以如果x是一个负数且y不是一个整数,就会报错。
sqrt函数返回参数的平方根,如果参数为负,同样会报错。

14.6字符串转换’stdlib.h’
double atof(char const *string);
double strtod(char const *string,char **unused);

用法和上面14.3类似,返回的是double

14.6排序和查找

最后记录下标准库里面自带的排序和查找函数
qsort函数在一个数组中以升序的方式对数据进行排序,由于他是和类型无关的,所以你可以使用qsort排序任意类型的数据,只是数组中的元素长度固定。

void qsort(void *base,size_t n_elements,size_t el_size,
        int(*compare)(void const *,void const * ));

第一个参数指向需要排序的数组,第二个参数指定数组中元素的数目,第三个参数指定每个元素的长度(以字符为单位)。第四个参数是一个函数指针,一般为比较函数。在排序时候,qsort调用这个函数对数组中的数据进行比较,通过传递一个指向合适的比较函数的指针,你可以实用qsort函数排序任意类型的数组。
比较函数接受两个*void参数,在比较重必须强制类型转换,具体说明见9.1,例如:

//使用qsort对一个元素为某种结构的数组进行排序
#include <stdlib.h>
#include <string.h>
typedef struct {
    char key[10];           /*数组排序关键字
    int  other_data;        /*与关键字关联的数据

}Record
int compare(void const *a, void const *b){
            return strcmp((Record*)a)->key,((Record*)b)->key);
}
int main()
{
    Record array[ 50 ];
    qsort(array ,50 ,sizeof(Record) ,compare);
/*此时数组已排序完毕*/
return  EXIT_SUCCESS;


}

bsearch函数在一个已经排序好的数组中用二分法查找一个特定元素。

    void *bsearch(void const *key,void const *base ,size_tn_elements,
    size_t el_size,int (*compare)(void const *,void const *));

第一个参数只想你要查找的值,第二个参数指向查找的数组,第三个参数指定数组元素的数目,第四个参数制定每个元素的长度,最后一个参数适合sqort中一样指向比较函数的指针)。
bserach会返回一个指向查找到的数组元素的指针,若未找到会返回NULL。
用法上面类似,依然以上面的例子:

//使用bsearch在一个元素为某种结构的数组进行查找
#include <stdlib.h>
#include <string.h>
typedef struct {
    char key[10];           /*数组排序关键字
    int  other_data;        /*与关键字关联的数据

}Record
int compare(void const *a, void const *b){
            return strcmp((Record*)a)->key,((Record*)b)->key);
}
int main()
{
    Record array[ 50 ];
    Record key;
    Record *ans;


    qsort(array ,50 ,sizeof(Record) ,compare);
    /*此时数组已排序完毕*/

    //创建一个关键字结构并在数组中查找
    strcpy(key.key,"value");
    ans=bsearch(&key,array,50,sizeof(Record)),compare);
    //现在ans指向关键字字段与值匹配的数据元素,如果无匹配,ans为NULL
return  EXIT_SUCCESS;


}

到此《C和指针》粗略地看完了,还是很有收获的,了解到许多没接触到的知识和用法,同时感受到写博客带来的好处,不但熟练了代码,也在写的过程中加深了理解,感受到技术与人分享的快乐,以后会将之前所做的项目经验和总结搬到博客上,希望自己可以坚持下去,与大神共勉!

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛应用于系统编程和嵌入式开发的高级编程语言。函数指针C语言中的一个重要概念,它可以指向函数,并且可以通过函数指针来调用函数。快速排序算法是一种常用的排序算法,它的核心思想是通过分治的策略将一个大问题分解为多个小问题,并通过递归的方式解决这些小问题。 下面是C语言中使用函数指针实现快速排序算法的示例代码: ```c #include <stdio.h> // 交换两个元素的值 void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } // 快速排序的分区函数 int partition(int arr[], int low, int high) { int pivot = arr[high]; // 选取最后一个元素作为基准 int i = (low - 1); // 定义一个指针,用于指向小于基准的元素 for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return (i + 1); } // 快速排序函数 void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); // 将数组分区,并获取分区点的位置 quickSort(arr, low, pi - 1); // 对分区点左边的子数组进行快速排序 quickSort(arr, pi + 1, high); // 对分区点右边的子数组进行快速排序 } } // 打印数组元素 void printArray(int arr[], int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); } int main() { int arr[] = {10, 7, 8, 9, 1, 5}; int n = sizeof(arr) / sizeof(arr[0]); printf("原始数组:"); printArray(arr, n); quickSort(arr, 0, n - 1); printf("排序后的数组:"); printArray(arr, n); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值