目录
一.指针
一.9.1-1取地址符的用法
#include<stdio.h>
int main ()
{
int i=0;
int p;
//强制转换使p为int型的地址
p=(int)&i;
printf("0x%x\n",&p);
//%p是16位进制打印地址,要输出地址要用%p
printf("%p\n",&i);
//p=(int)&i++;错误!&右边必须是变量
int a[10];
//前三个输出一样的地址,最后一个地址多了4,多了一个int的空间
printf("%p\n",&a);
printf("%p\n",a);
printf("%p\n",&a[0]);
printf("%p\n",&a[1]);
return 0;
}
二.9.1-2指针变量
#include<stdio.h>
void x(int *p)
{
//*是单目运算符,用来访问该地址的变量,即p的值
printf("%d\n",*p);
//通过*p来改变p的值
*p=27;
}
int main ()
{
int i=6;
x(&i);
printf("%d\n",i);
return 0;
}
三.9.1-3指针的用途
#include<stdio.h>
//用途一:当需要返回多个变量时用指针
void swap(int *p,int *q)
{
int t=*p;
*p=*q;
*q=t;
}
//用途二:当返回值可能出错时用指针
void chu(int x,int y,int *result)
{
int ret=1;
if(y==0)
{
ret= 0;
}
else
{
*result=x/y;
}
return ret;
}
int main ()
{
int a=5,b=6;
swap(&a,&b);
printf("a=%d\nb=%d\n",a,b);
int x=10,y=2,result;
if(chu(x,y,&result))
{
printf("%d",result);
}
return 0;
}
四.9.1-4 指针与数组
#include<stdio.h>
//int a[]实际上是指针,指向a[0]
//数组变量本身表达地址(取地址不需要用&),但是数组的单元表达不是(取地址要用&)
void arr(int a[])
{
printf("arr sizeof(a)=%lu\n",sizeof(a));
}
int main ()
{
int a[]={1,2,3,4,5,6,7,8,9,10};
printf("main sizeof(a)=%lu\n",sizeof(a));
arr(a);
//p是一个指针指向数组时,可当作数组来用
int *p=&a;
printf("p[1]=%d",p[1]);
return 0;
}
五.9.1-5指针与const
#include<stdio.h>
void f(const int*i)
{
//通过const指针来传递地址可以让传递的量保持不变
//并且可以使非const转化为const
}
int main ()
{
int i=16;
int j;
//这个指针是const,表示该指针只能指向i的地址不能再指向其他地址
//*p=26是可以的,但是p++不行,因为*p是改变i的值,p++是改变p所指的地址
int * const p=&i;
//int*是const,表示q可以指向其他地址,但是不能通过*q来改变i的量
//注意,q所指的i可以改变如i=26;
const int *q=&i;
q=&j;
//const 在*的左边或右边决定int*是const 还是指针是const
return 0;
}
六.9.2-1指针的运算
#include<stdio.h>
int main ()
{
//如下所示,指针p+1所加并非1而是它的类型
//如sizeof(char)=1就加1,sizeof(int)=4则加4
//
char ac[]={0,1,2,3,4,5,6,7,8,9,-1};
char *p=ac;
printf("p =%p\n",p);
printf("p+1 =%p\n",p+1);
// *(p+n)<->ac[n];
while(*p!=-1)
{
//*是运算符,优先级没++高所以*p++的意思是:取p所指的那个数据的值,再让p+1即指向下一位地址
*p++;
}
//不同类型的指针是不能直接赋值的,可以强制转换(初学者算了)
int ai[]={0,1,2,3,4,5,6,7,8,9,};
int *q=&ai[0];
printf("q =%p\n",q);
printf("q+1 =%p\n",q+1);
//*(q+1)是指q指向下一位地址
//注意*q+1无任何意义,因为其作用是使q指向的地址+1而一个int需要+4才能到第二位
printf("q+1=%d\n",*(q+1));
int *q1=&ai[5];
//实际上指针相减所得并非地址之差,而是地址之差/sizeof(...)
printf("q1-q=%d\n",q1-q);
return 0;
}
七.9.2-2动态内存分配
1.需要包含头文件<stdlib.h>
2.a=malloc(n*sizeof(char) )申请一块有n个char的空间
3.(int*)malloc(n*sizeof(char) )强行使char转换成int
4.使用完后需释放内存free( a )
5.若申请内存没释放则会使程序运行内存下降
6.free过了再free程序会崩溃
7.改变了地址去free,程序也会崩溃
二.字符串
一.10.1-1字符串
1.以整数0结尾的字符串
2.0和‘\0’是一样的,但是和‘0’不同
3.0标志字符串的结束,但它字符串的一部分
4.字符串以数组的方式存在,可用数组或指针的形式访问
5.string.h里有很多处理字符串的函数
6.不能用运算符对字符串进行运算
二.10.1-2字符串变量
·
#include<stdio.h>
int main ()
{
//指针:这个字符串不知道在哪里
//需要动态分配空间
char *str="Hello";
//数组:这个字符串在这里
//作为本地变量自动被回收
char word[]="Hello";
return 0;
}
三.10.1-3字符串输入输出
#include<stdio.h>
int main ()
{
char string[8];
char string2[7];
//%s是读入一个单词(读到空格、TAB或回车为止)
//但此方法不安全,因为不知道string的长度
scanf("%s",string);
//这是安全的,因为最多只能读七个字符
scanf("%7s",string2);
printf("%s",string);
/*
常见错误:
char *string;
scanf("%s,string);
以为char*是字符串类型,定义了一个字符串类型的变量string就可以直接使用了
由于没有对string初始化0,所以不一定每次运行都会出错
*/
//这是一个空字符,buffer[0]=='\0'
char buffer[100]="";
//这个数组的长度只有1!
char buffer2[]="";
return 0;
}
四.10.1-4字符串数组
#include<stdio.h>
int main ()
{
//二维数组第二个中括号必须有数来表示每位限制的字符数
char a[][10]=
{
"hello",
"bewoew",
"dsadsa"
};
return 0;
}
五.字符串函数
一.10.2-1putchar 和 getchar
#include<stdio.h>
int main ()
{
//向标准输出写一个字符
//返回了几个字符,EOF(-1)表示失败
int putchar(int c);
//向标准输入读入一个字符
//返回类型是int 是为了返回EOF(-1)
int getchar(void);
int ch;
while(ch=getchar()!=EOF)
{
putchar(ch);
}
return 0;
}
以下函数需要用到头文件string.h
二.10.2.2 strlen
作用:用来计算字符串长度
使用方法如下
printf ( "%lu", strlen ( a ) );
代码如下
size_t mystrlen(const char*s)
{
int cnt=0;
while (s[cnt]!='\0')
{
cnt++;
}
return cnt;
}
三.10.2-3strcmp
作用:用来比较两个字符串的大小
使用方法如下
int strcmp ( const char*s1 , const char*s2 );
若s1<s2 则返回 -1
若s1==s2 则返回0
若s1>s2 则返回1
数组代码如下
int mycmp(const char*s1,const char*s2)
{
int idx=0;
while(s1[idx]==s2[idx]&&s1[idx]!='\0')
{
idx++;
}
return s1[idx]-s2[idx];
}
指针代码如下
int mycmp(const char*s1,const char*s2)
{
while(*s1==*s2&&*s1!='\0')
{
s1++;
s2++;
}
return *s1-*s2;
}
四.10.2-4strcpy
作用:把一个字符串拷贝到另一个字符串上
使用方法如下
注意一下版本不安全,因为不知道字符串是否有足够空间
char *strcpy(char *restric dst , const char*restric src );
把src的字符拷贝到dst上
restric表明src和dst不重叠
数组代码和指针代码如下
char *mycpy(char*dst,const char*src)
{
//数组代码
int i=0;
while(src[i]!='\0')
{
dst[i]=src[i];
i++;
}
dst[i]='\0';
return dst;
//指针代码
char *ret=dst;
while(*dst++=*src++);
return ret;
}
安全版本如下:
char*strncpy( char*restric dst , const char*restric src , size_t n) ;
n表示最多能拷贝多少字符
五.10.2.5 strcat
作用:把一个字符串连接到另一个字符串上
安全版本如下:
char *strncat(char*restric s1 , const char*restric s2, size_t n);
六.10.2.6 strchr
作用:在字符串中寻找字符
使用方法如下:
char*strchr(const char *s , int c);从左往右找
char*strrchr(const char*s , int c);从右往左找
若返回NULL则表示没找到
寻找字符的代码如下,结果返回llo
char s[]="hello";
char*p=strchr(s,'l');
char*t=(char*)malloc(strlen(p)+1);
strcpy(t,p);
printf("%s\n",t);
free(t);
七.10.2.7 strstr和strcasestr
strstr作用:在一个字符串中寻找一个字符串
使用方法如下:
char*strstr(const char* s1,const char* s2);
strcasestr作用:在一个字符串中寻找一个字符串并且忽略大小写
使用方法如下:
char*strcasestr(const char* s1,const char* s2);
三.结构体
一.11.1-1枚举
定义:枚举是一种用户定义的数据类型
用法:用关键字enum以如下语法来声明
enum 枚举类型名字(可忽略){名字0 ,名字1,名字2,......,名字n};
注意:
在C语言中枚举变量其实是int,可以作为数输出,但实际上很(bu)少(hao)用
如果有意义上排比的名字,用枚举比用const int 方便
二.11.1-2结构类型
使用方法如下
struct 结构名字{ int a1, int a2, ..... } ;
用 . 运算符访问结构体成员
注意:结构体末尾需要加上分号
若该结构在函数内部声明则只能在该函数内使用
结构变量和数组变量不同,结构变量的名字并不是结构变量的地址,必须使用&运算符
代码如下
#include<stdio.h>
struct date
{
int year;
int month;
int day;
};
/*该代码是声明p1和p2两个结构变量
struct point{
int a;
int b;
} p1,p2;
*/
int main ()
{
struct date today;
today.day=24;
today.month=10;
today.year=2022;
printf("Today is %d-%d-%d\n",today.year,today.month,today.day);
//可用如下方式给结构变量赋值
struct date thisday={.month=10,.year=2022
};
struct date otherday={2022,10,24
};
return 0;
}
三.11.1.3结构与函数
1.结构作为函数参数
·整个结构可以作为参数的值传入函数
·这时候是在函数内新建一个结构变量,并复制调用者的结构的值
·也可以返回一个结构
·这与数组完全不同
2.输入结构
·没有直接的方式可以一次scanf一个结构
·记住C在函数调用时是传值的,可用如下方法进行main函数中的赋值
#include<stdio.h>
//声明一个结构体
struct point
{
int x;
int y;
};
//声明结构体函数
struct point getStruct(void);
int main ()
{
struct point y={0,0};
//让p与结构体函数的值相等
y=getStruct();
return 0;
}
struct point getStruct(void)
{
//在函数中定义一个结构体变量,为了给main中的结构体变量赋值
struct point p;
scanf("%d",&p.x);
scanf("%d",&p.y);
return p;
}
3.结构指针作为参数
·用->(减号+大于号)表示指针所指的结构变量中的成员 如:p->month=12;
#include<stdio.h>
//声明一个结构体
struct point
{
int x;
int y;
};
//声明结构体函数
struct point* getStruct(struct point*);
int main ()
{
struct point y={0,0};
getStruct(&y);
return 0;
}
//用指针的方式给结构体变量赋值
struct point* getStruct(struct point *p)
{
scanf("%d",&p->x);
scanf("%d",&p->y);
return p;
}
四.11.3-1类型定义
C语言中有函数typedef来自定义数据类型 如下:
typedef int length; 左边是原变量,右边是变量的别名.
作用:使length成为int 的别名(length可代替int出现在变量定义和参数声明中)
typedef struct Adate{
int month;
int year;
int day;
//使Date成为struct Adate的别名
}Date;
//如下
Date d={
12,2022,13
};