一、指针
1.1 指针的运算
i)算数运算
int a=100; | int *p=&a | |
+ | *p+n/a+n | 先取值,对值+n |
p+n/ &a+n | 向高字节方向偏移n倍数据类型字节大小 | |
*(p+n) | 向高字节方向偏移n倍数据类型字节大小,在取值 | |
&p+n | 向高字节方向偏移n倍指针字节大小n | |
- | *p-n/a-n | 先取值,对值-n |
p-n/ &a-n | 向低字节方向偏移n倍数据类型字节大小 | |
*(p-n) | 向低字节方向偏移n倍数据类型字节大小,在取值 | |
&p-n | 向低字节方向偏移n倍指针字节大小n | |
p-q | 连续空间,连个指针做减法计算之间元素的个数 | |
++ | (&a)++\++(&a) | 报错,一个变量的地址时常量 |
p++/++p | 向高字节方向偏移1数据类型字节大小 | |
++(*p) /++*p | 先取值,对值加1 | |
*++p | 先向高地址偏移1个数据类型大小,在取值 | |
(*p)++ | 先取值,先运算,在自增1 | |
*p++ | 先p++结合,但是++后缀运算,先取值,对地址向高字节方向偏移1个数据类型大小 | |
*(p++) | 先p++结合,但是++后缀运算,先取值,对地址向高字节方向偏移1个数据类型大小 | |
-- | 类似++运算 |
ii)赋值运算
= += -=
p+1 只是参与运算,不改变p自身的指向
p=p+1,参与运算,改变p的指向
= | int *p=&a | 指针p指向a的地址,把a的地址赋值给p |
+= | p+=2 | p改变指向,向高字节方向偏移2个数据类型字节大小 |
-= | p-=2 | p改变指向,向低字节方向偏移2个数据类型字节大小 |
iii)关系运算
> >= <
> | 大于 | p>q |
>= | 大于等于 | p>=q |
小于 | p | |
小于等于 | p | |
== | 等于 | p==q |
!= | 不等于 | p!=q |
使用指针实现字符串逆转
#include<stdio.h>
#include<string.h>
int main() {
char arr[127] = "";
scanf("%126s", arr);
char* p = arr;
int len = strlen(arr);
char *q= arr + len - 1;
int temp;
while (p < q) {
temp = *p;
*p = *q;
*q = temp;
p++;
q--;
}
printf("%s\n", arr);
return 0;
}
1.2 值传递和地址传递
1.3 指针和一维数组
指针指向数组时直接指向数组名即可,等同于指向数组首元素的地址
int arr[3];
int *p=arr;//int *p=&arr[0]
值:arr[i] -->*(arr+i) -->*(&arr[0]+i)
p[i] --->*(p+i) --->*(&p[0]+i)---->*p++
地址: &arr[i] -->arr+i --->&arr[0]+i
&p[i] --->p+i ---->&p[0]+i --->p++
指针实现冒泡排序&简单选择排序
#include <stdio.h>
#include<string.h>
#define _CRT_SECURE_NO_WARNINGS
void bubble_up(int *p,int len) {
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
if (*(p + j) > (*(p + j + 1))) {
int temp = *(p + j);
*(p + j) = *(p + j + 1);
*(p + j + 1) = temp;
}
}
}
for (int k = 0; k < len; k++) {
printf("%d ", *(p + k));
}
printf("\n");
}
void simple_selection_down(int* p, int len) {
int max = 0;
for (int i = 0; i < len - 1; i++) {
max = i;
for (int j = i+1; j < len; j++) {
if (*(p + max) < *(p + j)) {
max = j;
}
}
if (max != i) {
int temp = *(p + max);
*(p + max) = *(p + i);
*(p + i) = temp;
}
}
for (int k = 0; k < len; k++) {
printf("%d ", *(p + k));
}
}
int main() {
int arr[10] = { 0 };
int len = sizeof(arr)/sizeof(arr[0]);
for (int m = 0; m < len;m++) {
scanf("%500d", arr+m);
}
int* p = arr;
printf("冒泡:\n");
bubble_up(arr, len);
printf("简单选择:\n");
simple_selection_down(arr, len);
return 0;
}
1.4 指针和字符串
计算机中分为这几个区,字符串数组之所以能修改,是因为在栈区定义了个数组,复制静态只读取中的字符串,然后在栈区中操作,如果只是指针指向的字符串不能修改!!!但可以读取
字符串连接 数组和指针两种方式
#if 1
void my_strcat(char* dest, char* src) {
while (*dest != '\0') {
dest++;
}
int i= 0;
while (*(src+i)) {
*(dest+i)= *(src+i);
i++;
}
}
#endif
#if 0
void my_strcat(char *dest,char *src)
{
int i=0
for(i=0;dest[i]!='\0';i++);
for(int j=0;src[j]!='\0';j++)
{
dest[i++]=src[j];
}
dese[i]='\0';
}
#endif
作业
1.
错误在于char型数组string大小只有10字节,但是指针str1将11字节的字符串给他,发生越界
2.
错误在于将6字节的hello\0放入1字节大小的a中,导致缓冲段溢出
3.
错误在于指针s指向的是字符串常量,而字符串常量是在静态只读段的,只能读取不能修改
4.
只能计算0-99的和,在i==100时无法进入循环。未初始化指针MyData,对野指针操作会导致程序崩溃。初始化时sum没清零,之后是随机值。MyData在第一个循环之后已经越界到后面的地址了,第二个循环没在0的地址,再++会越界到另一片内存上。