1.指针定义:是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方 的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为指针。
#include<stdio.h>
int main()
{
int a = 10; //在内存中开辟一个空间
int* p = &a; //这里我们对变量a,取出它的地址,可以使用&操作符
//将a的地址存放到p变量中,p就是一个指针变量
return 0;
}
指针就是变量,用来存放地址的变量(存放在指针中的值都被当成地址处理)
指针是用来存放地址的,地址是唯一标识一块地址空间的
指针的大小在32位平台是4个字节,在64位平台是8个字节
#include<stdio.h>
int main()
{
int a = 0x11223344;
char *pc = &a;
*pc = 0;
return 0;
}
指针类型决定了指针进行解引用操作的时候,能够访问空间的大小
int* p; *p能访问4个字节
char* p; *p能访问1个字节
double* p; *p能访问8个字节
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。比如:char *的指针解引用就只能访问一个字节,而int *的指针能访问4个字节
#include<stdio.h>
int main()
{
int a = 0x11223344;
int* pa = &a;
char* pc = &a;
printf("%p\n", pa);
printf("%p\n", pa+1); +4
printf("%p\n", pc);
printf("%p\n", pc+1); +1
return 0;
}
//指针类型决定了:指针走一步走多远(指针的步长)
2. 野指针:指针指向的位置是不可知的(随机的,不正确的,没有明确限制的)
在指针的使用中,往往造成错误最多的就是出现了野指针,因此在使用指针时一定要注意野指针,三种野指针示例如下:
#include<stdio.h>
int main()
{
int a;//局部变量不初始化,默认是随机值
int* p;//局部的指针变量,就被初始化随机值
*p = 20;
return 0;
}
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i < 12; i++)
{
p++;//当指针指向的范围超出数组arr的范围时,p就是野指针
}
return 0;
}
#include<stdio.h>
int* test()
{
int a = 10;
return &a;
}
int main()
{
int* p = test();
*p = 20; //指针指向的空间释放
return 0;
}
那该如何规避野指针呢?有两种方法
(一)指针初始化,小心指针越界
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;//初始化
int* p = NULL;//NULL用来初始化指针的,给指针赋值
}
(二)指针指向空间释放即使置NULL,指针使用之前检查有效性
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;
*pa = 20;
pa = NULL;//使置NULL
//
if (pa != NULL)
{
}
}
3.指针运算
1)指针+-整数
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int sz = sizeof(arr)/ sizeof(arr[0]);
int* p = arr;
for (i = 0; i < sz; i++)
{
printf("%d ", *p);
p = p + 1;
}
}
2) 指针-指针(得到的是指针中间的元素个数,前提是在同一块空间内进行)
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", & arr[9] - &arr[0]);
return 0;
}
#include<stdio.h>
int my_strlen(char* str)
{
char* start = str;
char* end = str;
while (*end != '\0')
{
end++;
}
return end - start;//指针-指针
}
int main()
{
//strlen -求字符串长度
//递归 -模拟实现了strlen -计数器的方式1,递归的方式2
//
char arr[] = "bit";
int len=my_strlen(arr);
printf("%d\n", len);
return 0;
}
4.指针和数组
1) 指针
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n", & arr[0]);
//&arr - &数组名-数组名表示整个数组,&数组名,取出的是整个数组的地址
printf("%p\n", &arr);
//sizeof(arr) - sizeof(数组名)表示整个数组 -sizeof(数组名)表示整个数组的大小
return 0;
}
&arr - &数组名-数组名表示整个数组,&数组名,取出的是整个数组的地址
sizeof(arr) - sizeof(数组名)表示整个数组 -sizeof(数组名)表示整个数组的大小
除以上两种情况外,所有取数组名取的是该数组的首元素地址
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = arr;//指针存放数组首元素的地址
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
//for (i = 0; i < 10; i++)
//{
// printf("%p ===== %p\n", p + i, &arr[i]);
//}
}
2)二级指针
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;
int** ppa = &pa;//ppa就是一个二级指针
printf("%d\n", *ppa);
return 0;
}
3) 指针数组,是用来存放指针的数组
#include<stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* arr[3] = { &a,&b,&c };//指针数组
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%d ", *(arr[i]));
}
return 0;
}
5. 指针练习题
1)写一个函数求a的二进制(补码)表示中有几个1
方法一
#include<stdio.h>
int count_bit_one(unsigned int n)
{
int count = 0;
while (n)
{
if (n % 2 == 1)
{
count++;
}
n = n / 2;
}
return count;
}
int main()
{
int a = 0;
scanf("%d", &a);
int count=count_bit_one(a);
//13
//00000000000000000000000000001101
//
printf("count=%d\n", count);
return 0;
}
方法二
#include<stdio.h>
int count_bit_one(unsigned int n)
{
int count=0;
while(n)
{ n=n&(n-1);
count++;
}
return count;
}
int main()
{
int a = 0;
scanf("%d", &a);
int count=count_bit_one(a);
//13
//00000000000000000000000000001101
//
printf("count=%d\n", count);
return 0;
}
2)求二进制中不同位的个数 比如两个整型数的二进制表达中,有多少个比特位不同
#include<stdio.h>
int get(int m, int n)
{
int tmp = m ^ n;
int count = 0;
while (tmp)
{
tmp = tmp & (tmp - 1);
count++;
}
return count;
}
int main()
{
int m = 0;
int n = 0;
scanf("%d%d", &m, &n);
int count = get(m,n);
printf("count=%d\n", count);
return 0;
}
3)打印二进制的奇数位和偶数位,分别进行打印序列
#include<stdio.h>
void print(int m)
{
int i = 0;
printf("奇数位:\n");
for (i = 30; i >= 0; i -= 2)
{
printf("%d", (m >> i) & 1);
}
printf("\n");
printf("偶数位:\n");
for (i = 31; i >= 1; i -= 2)
{
printf("%d", (m >> i) & 1);
}
printf("\n");
}
int main()
{
int m = 0;
scanf("%d", &m);
print(m);
}
4)使用指针打印数组内容
#include<stdio.h>
void print(int* p, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
}
int main()
{
int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr, sz);
}
5)实现字符串的逆序
方法一
#include<stdio.h>
#include<string.h>
void reverse(char arr[])
{
int left = 0;
int right = strlen(arr) - 1;
while (left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{
char arr[] = "abcdef";
reverse(arr);
printf("%s\n", arr);
return 0;
}
方法二、不使用库函数strlen实现字符串的逆序
#include<stdio.h>
int my_strlen(char* str)
{
int count = 0;
while (*str != '0')
{
count++;
str++;
}
return count;
}
void reverse(char arr[])
{
int left = 0;
int right = my_strlen(arr) - 1;
while (left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{
char arr[] = "abcdef";
reverse(arr);
printf("%s\n", arr);
return 0;
}
方法三、不使用库函数并使用递归的方法实现对字符串的逆序
#include<stdio.h>
int my_strlen(char* str)
{
int count = 0;
while (*str != '0')
{
count++;
str++;
}
return count;
}
void reverse_string(char* arr)
{
char tmp = arr[0];
int len = my_strlen(arr);
arr[0] = arr[len - 1];
arr[len - 1] = '\0';
if (my_strlen(arr + 1) >= 2)
reverse_string(arr + 1);
arr[len - 1] = tmp;
}
int main()
{
char arr[] = "123";
reverse_string(arr);
printf("%s\n", arr);
return 0;
}
6)输入一个数,计算各位数之和
#include<stdio.h>
int DigitSum(unsigned int num)
{
if (num > 9)
{
return DigitSum(num / 10) + num % 10;
}
else
return num;
}
int main()
{
unsigned int num = 0;
scanf("%d", &num);
int ret = DigitSum(num);
printf("ret=%d\n", ret);
}
7)定义一个数组,将数组置为0,并且将数组的内容逆序输出
#include<stdio.h>
void Init(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
arr[i] = 0;
}
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void reverse(int arr[], int sz)
{
int left = 0;
int right = sz - 1;
while (left<right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9 };
int sz = sizeof(arr) / sizeof(arr[0]);
//Init(arr, sz);//把数组初始化为0
print(arr, sz);
reverse(arr,sz);
print(arr, sz);
return 0;
}
8)把数组a和数组b的元素进行交换
#include<stdio.h>
int main()
{
int arr1[] = { 0,1,2,3,4,5 };
int arr2[] = { 9,8,7,6,5,4 };
int tmp = 0;
int i = 0;
int sz = sizeof(arr1) / sizeof(arr1[0]);
for (i = 0; i < sz; i++)
{
tmp = arr1[i];
arr1[i] = arr2[i];
arr2[i] = tmp;
}
printf(arr1[i],arr2[i]);
return 0;
}