1 编写函数实现strlen,strcpy,strcat的功能
#include<stdio.h>
char *myStrcpy(char *dest,const char *src);
size_t myStrlen(const char *s);
char *myStrcat(char *dest, const char *src);
int main(int argc, const char *argv[])
{
char s1[64]={};
char s2[64]={};
printf("请输入第一个字符串:\n");
gets(s1);
printf("请输入第二个字符串:\n");
gets(s2);
printf("第一个字符串长度:%ld\n",myStrlen(s1));
printf("第二个字符串长度:%ld\n",myStrlen(s2));
myStrcat(s1,s2);
printf("执行myStrcat后:%s\n",s1);
myStrcpy(s1,s2);
printf("执行myStrcpy后:%s\n",s1);
return 0;
}
size_t myStrlen(const char *s){
int num=0;
while(*s!='\0'){
num++;
s++;
}
return num;
}
char *myStrcat(char *dest,const char *src){
int num1=0,num2=0;
while(*dest){
num1++;
dest++;
}
while(*src){
*dest=*src;
dest++;
src++;
}
return dest;
}
char *myStrcpy(char *dest, const char *src){
while(*src){
*dest=*src;
dest++;
src++;
}
*dest='\0';
return dest;
}
2 编写函数,实现冒泡排序
#include<stdio.h>
int *mySort(int a[],int n);
int main(int argc, const char *argv[])
{
int a[]={4,6,1,2,9,8,3,7,5};
int len=sizeof(a)/sizeof(a[0]);
printf("原数组:\n");
for(int i=0;i<len;i++){
printf("%d ",a[i]);
}
putchar(10);
mySort(a,len);
printf("排序后:\n");
for(int i=0;i<len;i++){
printf("%d ",a[i]);
}
putchar(10);
return 0;
}
int *mySort(int a[],int n){
int i,j;
for(i=0;i<n-1;i++){
for(j=0;j<n-1-i;j++){
if(a[j]>a[j+1]){
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
return a;
}
3 有一个字符串,找出重复次数最多的那个字符,比如"abccccdddee"中的字符’c’.
#include<stdio.h>
void *findMostTimes(char *s,int n);
char r[2];
int main(int argc, const char *argv[])
{
char str[]="abccccddee";
int len=sizeof(str)/sizeof(str[0]);
findMostTimes(str,len);
puts(str);
printf("%c出现次数最多,为%d次\n",r[0],r[1]-'0');
return 0;
}
void *findMostTimes(char *s,int n){
int i,j;
int num;
char c;
for(i=0;i<n;i++){
num=0;
c=s[i];
for(j=0;j<n;j++){
if(c==s[j])
num++;
}
if(num>(r[1]-'0')){
r[0]=c;
r[1]=num+'0';
}
}
}
1 空指针
指针的值不能时整型值,但空指针是个例外,空指针的值可以是一个纯粹的0。空指针的值为NULL,NULL是在‘stddef.h‘中定义的一个宏,它的值和任何有效指针的值都不同。NULL是一个纯粹的0,可能会被强制转换成’void*‘或’char*‘类型。
2 万能指针
void指针一般被称为通用指针或泛指针,它是c语言关于“纯粹地址”的一种约定。void指针指向某个对象,但该对象不属于任何类型。
int *ip;
void *p;
ip指向一个整型值,而p指向的值不属于任何类型。
可以用其他类型的指针来代替void指针,或者用void指针代替其他类型的指针,并且不需要进行强制转换。
3 const修饰符
如果想阻止一个变量被修改,需要用到const修饰符。在给变量加上const修饰符的同时,通常需要对它进行初始化,因为在以后的任何时候都没有机会去修改它的值。
const修饰全局变量:该变量存放在.ro段上(常量区)
const修饰局部变量:该变量存放在栈上
4 指针常量与常量指针
int * const p //指针常量:指针在前,常量在后
这个p只能指向一个位置,而不能指向其他位置。指向的变量值可以改变。
const int *p = &a; //常量指针 :常量在前,指针在后
指向的变量值不能改变,但是可以改变这个指针指向的位置。
5 register关键词
如果一个变量用register来修饰,意味着该变量会作为一个寄存器变量,让该变量的访问速度达到最快。register修饰的变量会在寄存器中开辟空间,使得运行效率大大提高。寄存器空间不一定能申请到,如果申请不到,就会自动变成auto修饰.
在使用时需要注意:
① 待声明为寄存器变量的类型应该时CPU寄存器所能接受的类型,寄存器变量是单个变量,变量长度应该小于等于寄存器长度。
② 不能对寄存器变量使用取地址符,因为该变量没有内存地址。
③ 尽量在大量、频繁操作时使用寄存器变量,且声明的变量个数应该尽量少。
6 函数的参数
函数在调用时会把一些表达式作为参数传递给函数。函数定义中的参数是形式参数(形参),函数的调用者提供给函数的参数是实际参数(实参),在调用函数时,实际参数的值将被复制到形式参数中。
函数的传参方式一般分为三种:
全局变量传参:一般不用,因为全局变量本身就可以在函数的内部直接使用,不需要专门传参。
值传参:将实参的值传递给形参
地址传递:将实参的地址传递给形参
7 当数组作为参数传递给函数时,可以通过sizeof得到数组的大小吗?
不可以,当数组作为函数参数时,无法在程序运行时通过数组参数本身告诉函数数组的大小,因为函数的数组参数相当于指向该数组的第一个元素的指针。意味着把数组传递给函数效率很高,也意味着必须通过某种机制告诉函数 数组参数的大小。
可将数组及其大小同时传递给函数。
8 局部变量和全局变量
函数形参变量只有在被调用期间才能分配内存单元,调用结束后立即释放。这一点表明形参变量只有在函数内才是有效的,离开该函数就不能再使用了。这种变量有效性的范围称为变量的作用域。
局部变量:也称为内部变量,局部变量是在函数内进行定义说明的,其作用域仅限于函数内,离开函数后再使用这种变量是非法的。
全局变量:也称为外部变量,它是在函数外部定义的变量,不属于哪一个函数,属于一个源程序文件,其作用域是整个源程序。在函数中使用全局变量,一般应作全局变量说明,只有在函数内经过说明的全局变量才能被使用(函数之后定义的全局变量要声明)。
9 函数调用自身
这种情况称之为递归,一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
10 函数
函数就是将一对要执行的代码放在一个代码块中,然后给这个代码起个名字,只要使用这个名字,就相当于使用这段代码,所以说函数很好的解决了代码的重用性,函数的编写尽量保证函数的功能单一性。
1.通过函数名找到函数的入口地址(函数名就是地址) int main(int argc,char *argv[])
2.给形参分配空间
3.传参,传值(把实参的值传递给形参的值)(值传递,地址传递)
4.执行函数体
5.结果返回到调用的地方
6.释放空间(栈空间)
一 字符串处理函数
1.1 strcat
#include <string.h>
char *strcat(char *dest, const char *src);
功能:将src追加到dest的后面
参数:
dest:目的字符串
src:源字符串
返回值:追加后的字符串的首地址
char *strncat(char *dest, const char *src, size_t n);
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char ch1[32] = "helloworld"; //需要保证ch1的空间足够大
char ch2[] = "123456";
strcat(ch1,ch2);
printf("ch1 = %s\n",ch1);
char ch3[32] = "hello\0worldworldworld"; //
char ch4[] = "123456";
strcat(ch3,ch4); //将ch4拼接到ch3的后面,会从ch3的第一个\0开始覆盖,并且会在后面添加\0
printf("ch3 = %s\n",ch3);
for(int i = 0;i < 32;i++)
{
printf("%c [%d]\n",ch3[i],ch3[i]);
}
strncat(ch3,ch4,3); //将ch4的前3个字节拼接到ch3的后面
printf("ch3 = %s\n",ch3);
for(int i = 0;i < 32;i++)
{
printf("%c [%d]\n",ch3[i],ch3[i]);
}
return 0;
}
编程:自己实现strcat的功能
#include <stdio.h>
int main(int argc, const char *argv[])
{
char ch1[32] = "hello\0world";
char ch2[] = "he\0llo123456";
int i = 0,j = 0;
//找到ch1 \0的位置
while(ch1[i] != '\0')
{
i++;
}
//循环将ch2的值赋值给ch1
while(ch2[j] != '\0')
{
ch1[i] = ch2[j];
j++;
i++;
}
//最后加上\0
ch1[i] = ch2[j];
printf("ch1 = %s\n",ch1);
return 0;
}
1.2 strcmp
#include <string.h>
int strcmp(const char *s1, const char *s2);
功能:比较两个字符串的大小
参数:s1,s2两个字符串
返回值:
0: s1 = s2
<0: s1 < s2
>0: s1 > s2
int strncmp(const char *s1, const char *s2, size_t n); //用于比较s2的前n个字节是否和s1相等
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
/*
char s1[] = "helloworld";
char s2[] = "helloboy";
*/
/*
char s1[] = "hello\0world"; //strcmp比较的是两个\0之前的内容
char s2[] = "hello\0boy";
*/
char s1[] = "hellow";
char s2[] = "helloboyad12345648";
//int ret = strcmp(s1,s2);
int ret = strncmp(s1,s2,5); //比较s2的前5个字节是否和s1相等
if(ret == 0)
{
printf("s1 = s2\n");
}
else if(ret > 0)
{
printf("s1 > s2\n");
}
else
{
printf("s1 < s2\n");
}
return 0;
}
1.3 strcpy
#include <string.h>
char*strcpy(char *dest,const char *src);
功能:将src字符串赋值到dest字符串中
参数:
dest:目的字符串
src:源字符串
返回值:返回目的字符串的首地址
#include <stdio.h>
#include <string.h>
//strcpy:将src中的元素从第一个开始覆盖到dest的第一个元素
int main(int argc, const char *argv[])
{
char ch1[32] = "helloworld";
char ch2[] = "nihaobeijing";
strcpy(ch1,ch2); //strcpy前要保证ch1的空间足够大
printf("ch1 = %s\n",ch1);
char ch3[5] = {'h','e','l','l','o'};
char ch4[] = "nihao\0beijing";
//strcpy(ch3,ch4); //strcpy前要保证ch1的空间足够大
//printf("ch3 = %s\n",ch3);
strncpy(ch3,ch4,4);
printf("ch3 = %s\n",ch3);
return 0;
}
二 指针
2.1 指针的用途
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e5uhGLrF-1677223449478)(D:\1aaaasuqian\day\img}`Y4}}{U@IULFUKL9}3RHPV.png)]
使得程序简洁,紧凑,高效等
数据结构的表示
动态分配内存空间
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 100,b = 200;
int *p = &a; //表示定义一个指针变量p,指向a的首地址
*p = 200; //通过指针去修改a的值
p = &b;
*p = 300;
printf("a = %d,b = %d\n",a,b);
char ch = 'a';
int *q = (int *)&ch; //左右指针类型不一致,操作系统做了默认类型转换
//char *chq = &ch;
*q = 2989;
//*chq = 8888;
printf("ch = %c\n",ch);
return 0;
}
#include <stdio.h>
#include <stdbool.h>
int main(int argc, const char *argv[])
{
printf("sizeof(int *) = %ld\n",sizeof(int *));
printf("sizeof(char *) = %ld\n",sizeof(char *));
printf("sizeof(double *) = %ld\n",sizeof(double *));
printf("sizeof(short *) = %ld\n",sizeof(short *));
printf("sizeof(float *) = %ld\n",sizeof(float *));
printf("sizeof(bool*) = %ld\n",sizeof(bool *));
int a = 100;
char ch = 'a';
int *q = &a;
char *chq = &ch;
printf("q = %p\n",q);
printf("chq = %p\n",chq);
printf("q + 1 = %p\n",q + 1); //不同的数据类型,步长不一样,只有步长一样,才能相互赋值
printf("chq + 1 = %p\n",chq + 1);
return 0;
}
练习:
定义一个一维数组,例如:int a[6] = {1,2,3,4,5,6};
定义指针变量p保存第二个元素的地址,并将这个元素的值修改为2000
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a[6] ={1,2,3,4,5,6};
int *p = &a[1];
*p = 2000;
int i;
for(i = 0; i < 6;i++)
{
printf("%d ",a[i]);
}
putchar(10);
return 0;
}
三 指针变量的运算
指针运算的种类是有限的,它只能进行算术运算,关系运算和赋值运算。
3.1 算术运算符
+ p + n 指针向后偏移n个操作空间
- p - n 指针向前偏移n个操作空间
++ p++ 指针向后偏移1个操作空间(改变了p的指向)
-- p-- 指针向前偏移1个操作空间(改变了p的指向)
px - py: 两个指针相减,表示两个地址空间之间元素的个数(px和py指针的类型必须相同,否则没有意义)
注意:指针只能进行相减的运算,(+ * /)都没有意义。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int arr[6] = {10,20,30,40,50,60};
int *p1 = &arr[0];
printf("*p1 = %d\n",*p1);
p1++;
int *p2 = p1++;
printf("p1 = %d,p2 = %d\n",*p1,*p2);
printf("p1 - p2 = %ld\n",p1 - p2);
int y = *p1; //取值
printf("y = %d\n",y);
y = ++*p1;
printf("y = %d,*p1 = %d\n",y,*p1);
y = *p1++; //先*p1结合赋值给y,然后指针p1++;
printf("y = %d,*p1 = %d\n",y,*p1);
y = (*p1)++;
printf("y = %d,*p1 = %d\n",y,*p1);
return 0;
}
3.2 关系运算符
>: p1 > p2 p1的地址>p2的地址
< ...
>=
<=
!= 通常和NULL去进行比较
== 通常和NULL去进行比较
3.3 赋值运算符
int a = 1;
int *p = &a;
int *q = p; 指针变量之间可以赋值
练习:输入一个字符串,将字符串元素翻转
helloworld
…
dlrowolleh
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char str[32] ={0};
printf("请输入一个字符串:\n");
scanf("%s",str);
char *q = str,*p = &str[strlen(str) - 1];
/*while(q < p)
{
char temp = *q;
*q = *p;
*p = temp;
q++;
p--;
}*/
for(;q < p;q++,p--)
{
char temp = *q;
*q = *p;
*p = temp;
}
printf("str = %s\n",str);
return 0;
}
四 指针和一维数组
#include <stdio.h>
int main(int argc, const char *argv[])
{
int arr[32] = {1,2,3,4,5,6};
int *p = arr;
for(int i = 0 ; i < sizeof(arr)/sizeof(arr[0]);i++)
{
//printf("%d ",arr[i]); //下标法
//printf("%d ",*p++); //指针法
//printf("%d ",*(p+i)); //指针法
//printf("%d ",p[i]); //下标法
printf("%d ",*(arr+i)); //指针法
}
putchar(10);
char ch1[32] = "helloworld";
char *pch = ch1;
for(int i = 0 ; i < sizeof(ch1)/sizeof(ch1[0]);i++)
{
//printf("%d ",arr[i]); //下标法
printf("%c",*pch++); //指针法
//printf("%d ",*(p+i)); //指针法
//printf("%d ",p[i]); //下标法
//printf("%c",*(ch1+i)); //指针法
}
putchar(10);
char *s = "helloworld123";
char *ss = "helloworld123";
if(s == ss)
{
printf("s = ss\n");
}
else
{
printf("s != ss\n");
}
//printf("%s\n",s);
//for(int i = 0 ; i < sizeof(s)/sizeof(s[0]);i++)
for(int i = 0 ; i < 13;i++)
{
printf("%c",s[i]);
}
//s[8] = 'w'; //不可以修改.ro段上(常量区)里面的值
putchar(10);
ss = "nihao"; //可以改变ss指针的指向
printf("ss = %s\n",ss);
return 0;
}
练习1:通过指针实现strcpy函数的功能
#include <stdio.h>
int main(int argc, const char *argv[])
{
char ch1[6] = {'h','e','l','l','o','o'};
char ch2[32] = {0};
printf("请输入要拷贝的字符串:\n");
scanf("%s",ch2);
char *p = ch1;
char *q = ch2;
#if 0
while(*q != '\0')
{
/*
*p = *q;
p++;
q++;*/
*p++ = *q++;
}
*p = *q;
#endif
while((*p++ = *q++) != '\0');
//printf("ch2 = %s\n",ch2);
for(int i = 0 ; i < 6;i++)
{
printf("%c [%d]\n",ch1[i],ch1[i]);
}
return 0;
}
五 指针和二维数组
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a[3][4] ={1,2,3,4,5,6,7,8,9,10,11,12};
printf("%p\n",a);
printf("%p\n",a + 1);
//*a = a[0]
//**a = a[0][0]
//a[i][j]
printf("**a = %d\n",**a);
int i,j;
for(i = 0 ; i < 3;i++)
{
for(j = 0 ;j < 4;j++)
{
//printf("%d ",a[i][j]);
printf("%-5d ",*(*(a + i) + j));
}
putchar(10);
}
return 0;
}
六 数组指针
#include <stdio.h>
//如何判断复杂的数据类型(指针类型)
//右左法则:
int main(int argc, const char *argv[])
{
int a[3][4] = {10,20,30,40,50,60,70,80,90,100,110,120};
int (*p)[4] = a; //p:数组指针
//int *p1 = a[0];
//int **q = &p1;
//printf("q = %p\n",q);
//printf("q+1 = %p\n",q + 1);
for(int i = 0 ; i < 3;i++)
{
for(int j = 0 ;j < 4;j++)
{
printf("%-5d",p[i][j]);
}
putchar(10);
}
//printf("sizeof(a) = %ld\n",sizeof(a)); //可以通过数组名计算二维数组的大小
//printf("sizeof(p) = %ld\n",sizeof(p)); //不可以通过指针变量计算二维数组的大小
return 0;
}
七 指针数组
指针数组:本质是一个一维数组,数组的每一个元素是一个指针
例如:int *a[4];
#include <stdio.h>
int main(int argc, const char *argv[])
{
int *a[4];
int num1 = 100;
int num2 = 200;
int num3 = 300;
int num4 = 400;
a[0] = &num1;
a[1] = &num2;
a[2] = &num3;
a[3] = &num4;
int i;
for(i = 0 ;i < 4;i++)
{
printf("%d ",*a[i]);
}
putchar(10);
puts("*******************\n");
char *p[4];
char s1[] = "helloworld";
char s2[] = "hello nanjing";
char s3[] = "hello tianjing";
char s4[] = "hello beijing";
p[0] = s1;
p[1] = s2;
p[2] = s3;
p[3] = s4;
int j;
for(j = 0; j< 4;j++)
{
printf("p[%d] = %s\n",j,p[j]);
}
return 0;
}
作业
1.通过指针自己实现strcat函数的功能
#include <stdio.h>
int main(int argc, const char *argv[])
{
char s1[32] = "helloworld";
char s2[32] = "123456";
char *p = s1;
char *q = s2;
while(*p != '\0')
{
p++;
}
while(*q != '\0')
{
*p = *q;
p++;
q++;
}
*p = *q;
printf("s1 = %s\n",s1);
return 0;
}
2.实现atoi函数的功能 "123456" --> 123456
将数字型字符串转化成整型数据
char str[] = "123456";
int num;
....
"123456" -->123456;
printf("%d",num);
#include <stdio.h>
int main(int argc, const char *argv[])
{
char str[32] = {0};
printf("请输入一个字符串:\n");
scanf("%s",str);
char *p = str;
int num;
int sum = 0;
while(*p != '\0')
{
if(*p >= '0' && *p <= '9')
{
num = *p - 48;
sum = num + sum*10;
}
else
{
printf("您输入的不是一个数字型字符串!\n");
break;
}
p++;
}
printf("sum = %d\n",sum);
return 0;
}
3.输入一个字符串,输出字符串中有多少个空格
#include <stdio.h>
int main(int argc, const char *argv[])
{
char str[32] = {0};
printf("请输入一个字符串:\n");
scanf("%[^\n]",str);
char *p = str;
int space_num = 0;
while(*p != '\0')
{
if(' ' == *p)
{
space_num++;
}
p++;
}
printf("%s中有%d个空格\n",str,space_num);
return 0;
}
4.输入一个字符串,将所有的大写字母转化为小写字母,小写字母转化为大写字母,所有的数字型字符转化为-,其它字符用*表示。
Hello123;''-->hELLO---***
#include <stdio.h>
int main(int argc, const char *argv[])
{
char str[32] = {0};
printf("请输入一个字符串:\n");
scanf("%[^\n]",str);
char *p = str;
while(*p != '\0')
{
if(*p >= 'A' && *p <= 'Z')
{
*p += 32;
}
else if(*p >= 'a' && *p <= 'z')
{
*p -= 32;
}
else if(*p >= '0' && *p <= '9')
{
*p = '-';
}
else
{
*p = '*';
}
p++;
}
printf("str = %s\n",str);
return 0;
}