指针
指针变量
- int *p: *代表将来变量p存储的是地址.
- int :代表将来是存储整型变量的地址
int a;
int *p;
p=&a;
*p=7;
int *q=&a ;
*q=9;
指针的指针
int a=5;
int *p=&a;
int **q=&p;
*(*q)=5;
- int **q ,就比如int (p),所以就是指向指针变量的指针变量,
int *p,表示指向整型变量的指针变量.
- 数组名就是首元素的的地址
int array[5]={1,2,3,4,5};
int *p;
p=array;
p++;
//p+i;表示指向第i个元素的地址,也可以用array+i来表示第i个元素的地址。
// &p[i]:也可以表示取第i个元素的地址
// array[i]:表示取第i个元素,也可以用p[i],还可以用*(p+i)以及*(array+i)来表示取第i个元素的值。
// array++,是错误的,数组名不可以++,可是p++是可以的。
- const int a=9;constant,如果一个变量使用const修饰,代表这个变量属性只读,不可写(不可改变).
- constant变量只能在定义的时候进行初始化.
- int const a;与const int a;是相同的,都代表a变量可读不可写
-
int a=9;
const int *p=&a;
*p=10;
//int const *p=&a;
//如果const是写在*的左边,代表这个变量将来如果用p访问变量的时候,内容只读,这两种写法的效果相同.
int a=9;
int b;
int *const p=&a;
//如果const写在*号的右边,代表这个指针变量本身的内容只读,不可更改
int a=9;
int b;
const int *const p=&a;
//如果*两边都有const,代表p所指向的内容只读,p本身的内容只读.
指针数组
- 先算[],代表他是一个数组,再算*,代表这个数组所有的元素都是指针,int *p[3];
-
int a,b,c;
int *p[3]={&a,&b,&c};
*(p[0])=7;//p[0]=&a;*(p[0])=a;
- 同时定义多个指针变量:int p,q;
不能写成:int *p,q;就代表p是指针变量,q是整型变量.
二级指针
int a=;
int **p;
练习
- 定义一个整型数组,使用指针对数组进行排序
- 对一个数组,颠倒输出
- 运算优先级
- (),[ ],-> .
- !,~,++,--,+,- :这里面的+和-表示正负;
- *,/,%
- +,-
- <<,>>
- <,<=,>,>=
- ==,!=
- &
- ^
- |
- &&
- ||
- ?:
- =,+=,*=,/=,%=,&=,^=,!=,<<=,>>=
- ,
- () ==> 单目==>算数==>关系==>逻辑==>三目==>赋值==>,
- 单目==>双目==>三目==>
二维数组的定义
- int array[2][3];2代表行数,3代表列数.
- int array1[2][3]={{1,2,3},{4,5,6}};
- int array2[2][3]={1,2,3,4,5,6};
- int array3[2][3]={{[1]=3},{[2]=6}};
- int array4['a'][3]={1,2,3};
- 行号省略,去后面算元素的个数,找到最近的数是列的倍数:int array5[][3]={1,2,3,4};
- int array6[5][]={1,2,3,4};这种写法是错误的,列号不能省略.
访问二维数组元素
- 数组名[行下标][列下标];
- 行下标>=0&&行下标<行数 ,列下标>=0&&列下标<列数
- int array[2][3]={1,2,3,4,5,6};访问array[2][3]的元素是错误的,越界访问.
遍历打印二维数组元素
int i,j;
int array[2][3]={1,2,3,4,5,6};
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("array[%d][%d]=%d\n",i,j,array[i][j]);
}
}
#include "stdio.h"
int main()
{
int a[2][2]={3,10,21,1};
int max=a[0][0];
int i,j;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
if(a[i][j]>max)
{
max=a[i][j];
}
}
}
printf("max=%d\n",max);
return 0;
}
二维数组的地址
- 访问第i行首元素的地址:&array[i][0] || *(array+i)=array[i] || array+i
- 访问第i行第j列元素的地址:&array[i][j] || array[i]+j || *(array+i)+j
- 访问第i行第j列的值:array[i][j] || *(array[i]+j) || ((array+i)+j)
- array+i :是指向第i行的首元素的地址,但由于是指向行的地址,所以不能 *(array+i)这样取首元素的值.
- *((array+i)+j):表示第i+j行的首元素的地址
- array:实际上是指第0行的整个一维数组
int array[2][3]={1,2,3,4,5,6};
int (*p)[3]=arr;//先算(*p),代表p是一个指针变量,再算[3];代表这个指针将来指向一个大小为3的一维数组.称为数组指针也叫行指针.
int i,j;
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("array[%d][%d]=%d\n",i,j,p[i][j]);
}
}
函数
函数定义格式
数据类型 函数名(int a,int b,......)
{
}
//数据类型:[unsigend ]int,char,float,double,void(空)
函数定义注意点
- 函数不能嵌套定义
- 函数名不能与系统提供的函数名相等
- 函数不能重复定
- 如果函数的数据类型是int,char,float,那么这个函数必须要有return,return后面的值的数据类型必须要与函数的数据类型保持一致
- 如果函数的数据类型是void,那么函数可以有return,也可以没有return,如果有return的话,return后面没有数值.
- 函数定义的形参个数,必须要与函数调用时实参个数相同
- 形参变量的数据类型相同,也不能省略数据类型,比如:如下错误:void sum(int a,b);必须要写成void sum(int a,int b);
- 形参个数可以是多个,没有限制;形参变量的数据类型可以各不相同.
函数调用
- 函数结束的标志,当函数碰到return时,该函数return下面的语句不会被执行.
-
函数实参与形参
- 形参:形式上的参数,在函数定义大的时候存在
- 实参:有实际意义的参数,在函数调用的时候存在.
int a=8;// 这是全局变量a,在全局有用.定义在函数外部的变量
void 函数名()
{
int a=9;//这是局部变量的a,只能在定义函数{}内部使用//或者说是定义在函数内部的变量
}
#include "stdio.h"
void swap(int *a,int *b)
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}
int main()
{
int a=8,b=9;
printf("a=%d,b=%d\n",a,b);//a=8,b=9
swap(&a,&b);
printf("a=%d,b=%d\n",a,b);//a=9,b=8
return 0;
}
- 传值
- 传地址
函数的递归
变量的作用域
- 作用域是变量起作用或有效的区域.变量的作用域决定变量的可访问性
- **注意点: **如果全局变量和局部变量同名,局部变量会看不见全局变量的存在.
变量存储类型
变量按生存期分
- 静态变量
- 动态变量
局部变量
- 静态局部变量
- 自动局部变量
全局变量
- 静态全局变量
- 自动全局变量
#include "stdio.h"
void test()
{
static int a=9;
a++;
printf("a=%d\n",a);
}
int mian()
{
test();
test();
return 0;
}
// 结果为a=9,a=10;
指针与函数
函数指针:指向函数的指针
- void (p)()=test();//test是函数名;函数名是函数的入口地址
//先算(p),代表p是一个指针变量,再算(),代表将来p这个指针执行一个没有形式参数的函数,在看void,代表p指向的这个函数返回值是void类型
- 可以用test();//来调用函数,也可以用p();
- int jiecheng(int)//int (*p)(int)=jiecheng;p(5);
函数与数组
void printArr(int *p,int size)//或者将*p该为p[];如果在[]里写一个具体值是没用的,机器不去识别.
{
int i;
for(i=0;i<size;i++)
{
printf("p[%d]=%d\n",i,p[i]);
}
}
int main()
{
int array[6]={1,2,3,4,5,6};
printArr(array,sizeof(arr)/sizeof(int));
return 0;
}
#include "stdio.h"
void paiXu(int array[],int size)
{
int i,j,temp;
for(i=0;i<size-1;i++)
{
for(j=i+1;j<size;j++)
{
if(array[i]>array[j])
{
temp=array[i];
array[i]=array[j];
array[j]=temp;
}
}
}
}
int main()
{
int array[6]={12,23,1,2,45,3};
paiXu(array,sizeof(array)/sizeof(int));
for(i=0;i<6;i++)
{
printf("array[%d]=%d\n",i,array[i]);
}
return 0;
}
指针函数
int *xxx()
{
static int a;//如果是int a;则不能有返回值,因为释放空间之后,int a的地址也不存在了
return &a;
}
int main()
{
int *p=xxx();
}
int *xxx()
{
static int a=5;
printf("a=%d\n",a);
return &a;
}
int main()
{
int *p=xxx();
*p=8;
xxx();
return 0;
}
字符串
- char string[10]={'a','b','c'};
- char string1[10]={"hello"};
- hello存在文字常量区,但是string这个字符串存在栈区,对文字常量区的内容进行了一份拷贝,所以可以修改string字符串里面的变量
char string2[10]="hello";
string[2]='m'
printf("string2=%s\n",string2);
- 在栈区定义了一个p指针指向了文字常量区的内容,所以,不可以使用p对文字常量区的内容进行更改
char *p="hello";
p+4;
printf("p=%s\n",p);
>- 结果o;
char *p="hello";
p++;
printf("p=%s\n",p);
>- 结果为ello;
char *p="hello";
char *q="hello";
printf("p=%p\nq=%p\n",p,q);
栈区
- 栈区:存储局部变量
- 静态区(全局区):静态变量,全局变量
- 堆区:存放由程序员调用malloc函数时分配的空间
- 文字常量区:
printf("abcdefr\0qwe\n");
>- 结果为abcdefr:只会打印到\0以前的部分,遇到\0之后不会打印.
char string1[3]={'o','k'};
char string[2]={'h','e'};
int i;
for(i=0;i<2;i++)
{
printf("string[%d]=%p\n",i,string+i);
}
for(i=0;i<3;i++)
{
printf("string1[%d]=%p\n",i,string+i);
}
printf("%s\n",string);
>- 结果为:heok,原因是电脑碰到'\0'之后才会停止打印,否则会一直打印.'h','e'在前面是跟电脑内存分配有关的
字符串长度计算
#include "string.h"
#include "stdio.h"
void test()
{
char str[10]="hello";
long int length=strlen(str);
printf("length=%ld\n",length);
}
int main()
{
test();
return 0;
}
>- 结果为length=5;
字符串拷贝函数
- strcpy()将右边的字符串拷贝到左边的字符串里,而不是覆盖原来的一小部分
- 注意的问题:
- 左边字符串的大小必须要大于右边的字符串大小
- 左边的字符串不能是使用char *p定义出来的
#include "stdio.h"
int myCopy(char *str,char *str1)
{
while(*str!=0)
{
*str1=*str;
str++;
str1++;
}
*str1='\0';
}
int main()
{
char str1[10];
char str[10]="hello";
mycopy(str,str1);
printf("%s\n",str1);
return 0;
}
#include "string.h"
#include "stdio.h"
void test()
{
char str[10]="hello";
char str1[10]="xxxxxxx";
strcpy(str1,str);
printf("str1=%s\n",str1);
}
int main()
{
test();
return 0;
}
>- 结果为str1=hello;
字符串比较函数
- strcmp(string1,string2);如果两个字符串相同,结果为0,如果你的编译器比较高级,如果左边的字符串>右边的字符串,结果是(左边的不同的字符ASCII值-右边对应位上的字符ASCII值)。
- 如果编译器比较落后,左边>右边,结果为1,如果左边<右边,结果还是左边的不同的字符ASCII值-右边对应位上的字符ASCII值
字符串拼接函数
- stract()是将右边的字符串拼接到左边的字符串的后面
- 注意的问题:左边的字符串足够大
- 左边的字符串不能是使用char *p定义出来的
#include "string.h"
#include "stdio.h"
void test()
{
char str[10]="hello";
char str1[10]="world";
strcat(str,str1);
printf("str=%s\n",str);
}
int main()
{
test();
return 0;
}
>- 结果为:helloworld
字符串比较具体个数的字符
#include "stdio.h"
#include "string.h"
int main()
{
char str[20]="hellonihao";
char str1[20]="helloworld";
int result=strncmp(str1,str,5);//比较前面5个字符是否相等
printf("result=%d\n",result);
>- 结果为result=0;
}
strncpy()替换字符串前面的具体数目的字符
#include "stdio.h"
#include "string.h"
int main()
{
char str[20]="hellonihao";
strncpy(str,"wang",4);
printf("%s\n",str);
}
>- 结果为:wangonihao
strncat
#include "stdio.h"
#include "string.h"
int main()
{
char str[20]="hellonihao";
char str1[10]="worldxxx";
strncat(str,str1,5);
printf("%s\n",str);
}
>- 结果为:hellonihaoworld
输入字符串
#include "string.h"
#include "stdio.h"
int main()
{
char string[10];
scanf("%s",string);
printf("string=%s\n",string);
return 0;
}
>- 结果为:输入123,则string=123,输入hello,则string=hello
- 练习:写一个函数能吸收空格的
zhang san
string=zhang san
字符串数组
- char str[2][10]={"hello","world"};
指针数组
- char *p="123";
- char *p1="nihao";
- char *str1[2]={p,p1};//char *str1][2]={"123","nihao"};
//printf("p=%s\n",str1[0]);
结构体类型
- 可以将不同种数据类型组合在一起的集合.
struct;
- 结构体数据类型的定义
struct 结构体名
{
属性变量;(特征变量)
};
struct Person
{
char name[10];
char sex;
int height;
float score;
};//以下是结构体变量的定义
struct Person person;
结构体的初始化方法
-
.代表'的':
person.sex='m';
strcpy(person.name,"xxxx");
person.height=180;
person.score=90.5;
printf("name=%s\nsex=%c\nheight=%d\nscore=%f\n",person.name,person.sex,person.height,person.score);
-
struct Person person1={"xx1",'w',120,80.0};
printf("name=%s\nsex=%c\nheight=%d\nscore=%f\n",person1.name,person1.sex,person1.height,person1.score);
-
struct Person person2=person1;
printf("name=%s,sex=%c,height=%d,score=%f\n",person1.name,person1.sex,person1.height,person1.score);
内存对齐:
- 如果结构体里的成员变量都是基本数据类型的成员,那么第一个成员的变量内存从内存偏移量为0的位置,后面的成员变量从内存偏移量是他本身字节数的倍数开始分配。
- 如果结构体成员变量里面是集合类型,数组,结构体,枚举,那么成员变量。比如struct xxx{char ch,Int score}那么该结构体成员从内存偏移量是该结构体里面最大字节数的成员变量的倍数开始分配。
- 最后收尾的时候,总的字节数是最大成员变量(字节数)的倍数.
struct Person
{
char sex;//0
int height;//4--7
char ch;8(得9,根据条件3奥球倍数,所以为12)
};
struct Person
{
char sex;//0
char ch[10];//1--10
int height;//12--15
};//得16
printf("%d",sizeof(struct Person));
struct Person
{
char sex;//0
double score;//8-15
int height;//16-19
};//得24;
struct Person
{
char sex;//0
double score;//8-15
int height;//16-19
char ch[10]//20-29
};//得32
#include "stdio.h"
int main()
{
struct Birthday
{
int year;//0-3
int month;//4-7
int day;//8-11
};得12字节
struct Person
{
char name[10];//0-9
int score;//12-15
char sex;//16
struct Birthday birth;//20-31
};得32字节
struct Person person={"xxx",100,'m',{1990,1,1}};
printf("person.name=%s,birthday=%d/%d/%d\n",person.name,person.birth.year,person.birth.month,person.birth.day);
}
#include "stdio.h"
int main()
{
struct Birthday
{
int year;//0-3
double month;//8-15
int day;//16-19
};得24字节
struct Person
{
char name[10];//0-9
int score;//12-15
char sex;//16
struct Birthday birth;//24-47
};得48字节
struct Person person={"xxx",100,'m',{1990,1,1}};
printf("person.name=%s,birthday=%d/%d/%d\n",person.name,person.birth.year,person.birth.month,person.birth.day);
}
有无名结构体
- 有名结构体
struct Person
{
int a;
char b;
};
- 无名结构体
struct
{
int a;
char b;
}xx,xx1;
- 定义这个结构体数据类型的同时定义出来一个这个结构体类型的变量
struct Student
{
int score;
char sex;
}stu1[2]={{12,'m'},{13,'w'}};
指针
struct Person
{
int height;
char sex;
};
struct Person person;
struct Person *p=&person;
//(*p).sex='m';
//(*p).height=120;
//printf("person.height=%d,sex=%c\n",person.height,person.sex);
\\p->height=190;
\\p->sex='w';
\\printf("person.height=%d,sex=%c\n",person.height,person.sex);
- typedef将现有的数据类型定义成你想要的数据类型
typedef int I;
I i=
struct Student
{
char name[10];
int num;
};
typedef struct Student Student;
typedef struct Student
{
char name[10];
int num;
}Student;
Student stu={"xx",10};
printf("name=%s\nnum=%d\n",stu.name,stu.num);
- 结构体数据类型的定义一半放在函数的外面,供全局使用
结构体数组
#include "stdio.h"
typedef struct Student
{
char name[10];
int num;
}Student;
int main()
{
Student stu[4]={{"xx1",12},}
{"xx2",13},
{"xx3",14},
{"xx4",15}
};
}
int i;
for(i=0;i<4;i++)
{
printf("stu[%d].nume=%s,num=%d\n",i,stu[i].name,stu[i].num);
}
}
#include "stdio.h"
typedef struct Student
{
char name[10];
int num;
}Student,*pStudent;
int main()
{
Student stu[4]={
{"xx1",12},
{"xx2",13},
{"xx3",14},
{"xx4",15}
};
pStudent p=stu;
int i;
for(i=0;i<4;i++)
{
printf("stu[%d].nume=%s,num=%d\n",i,(*(p+i)).name,(*(p+i)).num);
}
return 0;
}
#include "stdio.h"
typedef struct Student
{
char name[10];
int num;
}Student,*pStudent;
int main()
{
Student stu[4]={
{"xx4",12},
{"xxa",13},
{"xxb",14},
{"xx1",15}
};
Student temp;
pStudent p=stu;
int i,j;
for(i=0;i<3;i++)
{
for(j=i+1;j<4;j++)
{
if(strcmp((*(p+i)).name,(*(p+j)).name)>0)
{
temp=*(p+i);
*(p+i)=*(p+j);
*(p+j)=temp;
}
}
}
for(i=0;i<4;i++)
{
printf("stu[%d].nume=%s,num=%d\n",i,(*(p+i)).name,(*(p+i)).num);
}
return 0;
}
#include "stdio.h"
int main()
{
int i,j;
int array[6]={12,3,2,45,6,76};
for(i=0;i<5;i++)
{
for(j=i+1;j<6j++)
{
if(array[minIndex]>array[j])
{
minIndex=j;
}
}
if(minIndex!=1)
{
int temp=array[i];
array[i]=array[minIndex];
array[minIndex]=temp;
}
}
for(i=0;i<6;i++)
{
printf("array[%d]=%d\n",i,array[i]);
}
return 0;
}
- 实现myStrcat(),myStrncmp(),myStrncpy()