目录
(一)用指针交换两个变量的值
#include<stdio.h>
void swap(int* a, int* b)
{
int temp;
temp= *a;
*a = *b;
*b = temp;
}
int main()
{
int a, b;
scanf("%d %d", &a, &b);
printf("交换前:%d,%d", a, b);
swap(&a, &b);
printf("交换后:%d,%d", a, b);
return 0;
}
(二)指针:
一个函数A通过调用函数B,来达到修改A中变量的值,必须传指针,在B中必须解引用。
int *p;
*p=10;
这是错误的,这个p是悬空指针,悬挂指针,野指针,并没有指向一个有效的地址。
p是指向一个变量的变量,所以一定要先指向一个变量,给那个变量赋值,才可以。
解一元二次方程时如果有两个根,要改变函数的定义,因为在C语言中只能返回一个或者0个值。
但是注意数组返回可以返回两个,一个是数组名,一个是数组长度。
char atr1[]="hello world";(是字符串数组,是字符串)
char *str2="hello world";(是字符串常量)
Hello world 需要十二个字节的空间,而指针只占四个字节,所以Hello world在指针里面是常量
str1[0]='x';(数组中每一个元素都可以被修改)
str2[0]='x';(会报错,运行崩溃)
#include<stdio.h>
#include<math.h>
int Fun(int a, int b, int c,double* x1, double* x2)
/*x1,x2称为输出函数,传递的是指针,在内部解引用,所以可以传出去*/
{
int d = b * b - 4 * a * c;
*x1 = (-b + sqrt(d)) / (2 * a);
*x2= (-b -sqrt(d)) / (2 * a);
return 2;/*因为只能返回0个或者1个值,所以我们在这里返回根的个数*/
}
int main()
{
double x1;
double x2;
Fun(1, -3, 2, &x1, &x2);
printf("%.2lf,%.2lf\n", x1, x2);
return 0;
}
(三)两个整数从大到小输出
#include<stdio.h>
#include<math.h>
void max(int* a, int* b)
{
if (*a < *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
}
int main()
{
int a, b;
scanf("%d %d", &a, &b);
max(&a, &b);
printf("%d,%d", a, b);
return 0;
}
(四)通过指针指向数组元素
定义的时候是*p=&a(万万注意)
一维数组arr的名字表示整个数组得到情况:
1.在定义数组的同一个函数中求sizeof。sizeof(arr)
2.在定义数组的同一个函数中,&arr+1表示加整个数组的大小。
int arr[10].&arr与&arr+1相差40个字节。
其他情况arr表示数组首地址。
int main()
{
int arr[10] = { 1,3,5,7,9,11,13,15,17,19 };
int* p = &arr[0];/*与int* p = arr;等价*/
/*int* p = arr;*/
printf("%d,%d\n", arr[0], *p);/*注意观察这两个是等价的*/
printf("%d\n", sizeof(arr));/*此句告诉我们arr可以代表整个数组,在这种情况下*/
printf("%d,%d\n", &arr, &arr + 1);
/*&arr与 &arr + 1相差四十个字节(也就是整个数组所占的字节)*/
return 0;
}
(五)通过指针访问(输出)数组中的所有元素
for (int i = 0; i < 10; i++)
{
printf("%d ", *p);
p++;
}
指针可以++,意思是加一个单元格
for (int i = 0; i < 10; i++)
{
printf("%d ", *p++);
}
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p+i));
}
指针的算术运算:前提是指针指向一个数组,保证程序不越界。
p+整数,p++,++p,p--,--p,p-i
int main()
{
int arr[10] = { 1,3,5,7,9,11,13,15,17,19 };
int* p = &arr[9];
for (int i = 0; i < 10; i++)
{
printf("%d ", *p);
p--;
}
return 0;
}
这个程序实现了数组的反序。
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p-i));
}
指针的关系运算:>,<,>=,<=,==,!=
for (int *p=arr;p!=&arr[10];p++)
{
printf("%d ", *p);
}
数组作为参数传递:数组仅仅表示数组首元素的地址。
传数组名和数组的长度。
#include<stdio.h>
void show(int* p, int n)
{
for (int i = 0; i < n; i++)
printf("%d ", p[i]);
printf("\n");
}
int main()
{
int arr[10] = { 1,3,5,7,9,11,13,15,17,19 };
show(arr, sizeof(arr) / sizeof(arr[0]));
return 0;
}
(六)用指针实现数组的反序
#include<stdio.h>
void show(int* p, int n)
{
for (int i = n-1; i>=0; i--)
printf("%d ", p[i]);
printf("\n");
}
int main()
{
int arr[10] = { 1,3,5,7,9,11,13,15,17,19 };
show(arr, sizeof(arr) / sizeof(arr[0]));
return 0;
}
void show(int* p, int n)
{
int temp;
for (int i = 0, j = n - 1; i < j; i++, j--)
{
temp = p[i];
p[i] = p[j];
p[j] = temp;
}
}
int main()
{
int arr[10] = { 1,3,5,7,9,11,13,15,17,19 };
show(arr, sizeof(arr) / sizeof(arr[0]));
for (int i = 0; i < 10; i++)
printf("%d ", arr[i]);
return 0;
}
for (int i = 0, j = n - 1; i < j; i++, j--)
{
temp = *(p+i);
*(p + i) = *(p+j);
*(p + j) = temp;
}
(七)选择法排序
#include<stdio.h>
#include<math.h>
void paixu(int* p, int n)
{
int temp;
int min;
for (int i = 0; i<n-1;i++)
{
min = i;
for (int j = i + 1; j < n; j++)
{
if (p[min] > p[j])
{
min = j;
}
}
temp = p[min];
p[min] = p[i];
p[i] = temp;
}
}
int main()
{
int arr[10] = { 1,9,5,3,2,4,6,8,7,0};
paixu(arr, sizeof(arr) / sizeof(arr[0]));
for (int i = 0; i < 10; i++)
printf("%d ", arr[i]);
return 0;
}
用指针的话就是把数组改成指针。
(八)用指针指向多维数组
类型 | 类型 | ||
int arr[4] | int brr[3][4] | ||
arr | int*x; | brr | int(*x)[4] |
首元素的地址 | 相当于第一行的地址,把每一行看做一个元素 | ||
arr+1 | int*x; | brr[0] | int*x; |
相当于第一行的元素地址,也就是一维数组的地址,和arr差不多 | |||
arr[0] | int x; | brr+1 | int(*x)[4] |
brr[0]+1 | int*x; | ||
brr[0][0] | int | ||
brr[0][0]+1 | int |
(九)输出二维数组所有元素的值
#include<stdio.h>
#include<math.h>
void show(int(*brr)[4], int row)/*注意注意注意多维数组的指针怎么表示*/
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < 4; j++)
{
printf("%4d", brr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
show(arr, 3);
return 0;
}
(十)const:不允许修改(其修饰的)内容
const a=10;
a=20;
这样是不对的,因为const已经把a的值固定住了,不能再把20赋值给她了。
基本类型对于const是透明的,const int a与int const a是等同的。
const只能修饰直接右边。
const int*p=&a;
*p就不能再变了,但是p的值可以变。
p=&b;这句话是可以的不会报错。
int *const p1=&c;
p1的值不能再变了,*p1就可以再变。
*p1=d;是可以的。00.
字符串和普通数组的区别:字符串可以通过‘\0’判断结尾,不需要传递长度
(十一)指向函数的指针
函数族
标准规定函数名也表示函数的入口地址。
int (*pfun)(int,int);
pfun一定是指针,该指针指向函数,函数参数为int,int,返回值为int,即pfun是一个函数指针
int max(int a,int b)
{
return a>=b?a:b;
}
.......
int main()
{
int (*pfun)(int,int);
pfun=max;或者pfun=&max;
...
}
(十二)动态内存
局部变量:分配的内存区域在栈,很小
动态内存使用的场景:
1.需要大容量内存2.在一个函数创建的内存在别的函数中还需要使用时
void:没有,可以修饰返回值和参数列表。
void*:没有类型信息的指针,这个指针仅仅是记录地址。
如何创建动态内存:
malloc:创建内存,需要引用<stdlib.h>,失败返回NULL,成功返回地址。
calloc:创建内存
realloc:创建内存
free:释放内存