字符串常量

#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
//数组名为首元素地址 str1和str2两个数组的首元素地址不同
const char *str3 = "hello bit.";//字符串常量
const char *str4 = "hello bit.";//常量字符串不能被修改 而且两个字符串相同 所以存放在一个地址
//常量
if (str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n"); // not same

if (str3 == str4)
printf("str3 and str4 are same\n"); //same
else
printf("str3 and str4 are not same\n");

return 0;
}

数组名

#include <stdio.h>
int main()
{
int arr[10] = {0};
printf("arr = %p\n", arr);
printf("&arr= %p\n", &arr);
printf("arr+1 = %p\n", arr + 1); //+1个int长度
printf("&arr+1= %p\n", &arr + 1);//+1个数组长度
return 0;
}
#include <stdio.h>
int main()
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int(*p)[10] = &arr; //把数组arr的地址赋值给数组指针变量p
return 0;
}
#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
//printf("%d ", *(*(arr+i)+j)); 数组其实就是指针
}
printf("\n");
}
}
void print_arr2(int (*arr)[5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d ", *(*(arr+i)+j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10},{12,42,52,22}};
print_arr1(arr, 3, 5);

print_arr2(arr, 3, 5); //二维数组的数组名为 第一行的地址

//总结
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
//可以数组指针来接收
return 0;
}
#include <stdio.h>

int main() //别绕进去了
{
int arr[5]; //整型数组 数组有5个元素 每个元素是整型
int *parr1[10]; //指针数组 数组有10个元素 每个元素是int*类型
int(*parr2)[10]; //数组指针 指针指向一个数组 数组有10个元素 每个元素是int类型
int(*parr3[10])[5]; //指针数组 数组存放10个元素 每个元素是数组指针
//接上句 指针指向的数组 数组有5个元素 每个元素是int类型
return 0;
}
#include <stdio.h>
void test(int arr[]) // ok
{
}
void test(int arr[10]) // ok 10可以不写 也可以随便写
{
}
void test(int *arr) // ok 传入的是首元素地址 是地址就能解引用
{
}
void test2(int *arr[20]) // ok
{
}
void test2(int **arr) // ok 二级指针 指针数组的数组名 为第一个元素的地址 然后再解引用
{
}
int main()
{
int arr[10] = {0};
int *arr2[20] = {0};
test(arr);
test2(arr2);
return 0;
}
void test(int *arr) // 错    是整型指针
{
}
void test(int *arr[5]) // 错 是数组
{
}
void test(int (*arr)[5]) // ok 数组指针 传过去的是二维指针第一行
{
}
void test(int **arr) // 错 这是二级指针
{
}
int main()
{
int arr[3][5] = {0};
test(arr);
}

一级指针传参

void test1(int *p)
{}
//test1函数能接收什么参数?
int main()
{
int a =10;
int* p =&a;
test1(&a);
test1(p);
return 0;
}

二级指针传参

#include <stdio.h>
void test(int **ptr)
{
printf("num = %d\n", **ptr);
}
int main()
{
int n = 10;
int *p = &n;
int **pp = &p;
test(pp);
test(&p);
int* arr[5];//指针数组
test(arr);
return 0;
}

函数指针

#include <stdio.h>
void test(int a)
{
printf("hehe\n");
}
int main()
{ //函数名 和 取地址+函数名 都是函数的地址
//printf("%p\n", test);
//printf("%p\n", &test);
int (*pa)(int) = test; //函数指针
(pa)(1);
(*pa)(1);
(**pa)(1);
(***pa)(1); //4种调用方式都可以 *可有可无 可多可少
//*pa(1); //()优先级大于* 这个会报错
return 0;
}
//代码1
(*(void (*)())0)();
// void (*)() 函数指针类型 void (*p)() p是函数指针
// (void (*)()) 强制类型转换成 函数指针类型
//把0强制类型转换成函数指针类型(0变成函数的地址)
//并且解引用 得到函数名 调用函数==>函数名()
//代码2
void (*signal(int, void (*)(int)))(int);
// signal(int, void (*)(int)) 这是函数名(参数列表)
// void (* )(int) 这是函数返回值
// void (*)(int) signal(int, void(*)(int)) 按理说应该这样写
// 为啥呢???
// typedef void (*)(int) pfun_t; 按理说应该这样重命名
// typedef void (*pfun_t) (int); 但是要把新名字 放到*号后面
// pfun_t(*signal(int,pfun_t)) 这是改造后的函数指针

函数指针用作转移表

#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}
int main()
{
int x, y;
int input = 1;
int ret = 0; //函数指针的应用
int (*p[5])(int x, int y) = {0, add, sub, mul, div}; //这是函数指针的数组 用作转移表
while (input)
{
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf("*************************\n");
printf("请选择:");
scanf("%d", &input);
if ((input <= 4 && input >= 1))
{
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = (*p[input])(x, y);
}
else
printf("输入有误\n");
printf("ret = %d\n", ret);
}
return 0;
}

指针和数组

void test(const char *str)
{
printf("%s\n", str);
}
int main()
{
void (*pfun)(const char *) = test; //这是一个指针

void (*pfunArr[5])(const char *str); //这是一个数组
pfunArr[0] = test;

void (*(*ppfunArr)[5])(const char *) = &pfunArr;
//void (*)(const char *) (*ppfunArr)[5] 数组指针 这是方便理解的写法
//(*ppfunArr)[5] 这是一个指针 指向一个数组 数组里存放5个函数指针类型的元素
return 0;
}

sizeof和strlen

#include <stdio.h>
int main()
{
//一维数组
int a[] = {1, 2, 3, 4}; // 64位机器 地址为8字节
printf("%d\n", sizeof(a)); // 16 数组名是首元素地址 2个例外
printf("%d\n", sizeof(a + 0)); // 8 (单独放)sizeof数组名 和 取地址数组名 表示整个数组
printf("%d\n", sizeof(*a)); // 4
printf("%d\n", sizeof(a + 1)); // 8
printf("%d\n", sizeof(a[1])); // 4
printf("%d\n", sizeof(&a)); // 8 数组的地址
printf("%d\n", sizeof(*&a)); // 16 数组的地址解引用是数组
printf("%d\n", sizeof(&a + 1)); // 8
printf("%d\n", sizeof(&a[0])); // 8
printf("%d\n", sizeof(&a[0] + 1)); // 8
//字符数组
char arr[] = {'a', 'b', 'c', 'd', 'e', 'f'};
printf("%d\n", sizeof(arr)); // 6
printf("%d\n", sizeof(arr + 0)); // 8 首元素的地址+0=首元素的地址
printf("%d\n", sizeof(*arr)); // 1 首元素地址解引用=首元素
printf("%d\n", sizeof(arr[1])); // 1
printf("%d\n", sizeof(&arr)); // 8
printf("%d\n", sizeof(&arr + 1)); // 8
printf("%d\n", sizeof(&arr[0] + 1)); // 8
printf("%d\n", strlen(arr)); // 随机值 数组后面放啥不清楚 找到\0为止
printf("%d\n", strlen(arr + 0)); // 随机值
//printf("%d\n", strlen(*arr)); // strlen传进去的是地址 传了‘a’为97 报错
//printf("%d\n", strlen(arr[1])); // 地址为98 报错
printf("%d\n", strlen(&arr)); // 随机值
printf("%d\n", strlen(&arr+1)); // 随机值-6
printf("%d\n", strlen(&arr[0]+1)); // 随机值-1

}