int main()
{
//本质上是把"hello bit"这个字符串的首字符的地址存储在了ps中
char* ps = "hello bit";
printf("%c\n", *ps);//h
char arr[] = "hello bit";//把字符串放入字符数组
printf("%s\n", ps);//hello bit %s 给起始位置的地址打印字符串
printf("%s\n", arr);//hello bit
//*ps = 'w';//err不能更改 引发了异常: 写入访问权限冲突。
arr[0] = 'w';//可以更改
printf("%s\n", arr);//wello bit
return 0;
}
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
char* str3 = "hello bit.";//常量字符串,不能更改
char* str4 = "hello bit.";
//*str3 = 'w';err
if (str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if (str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
int main()
{
//char ch = 'w';
//char* pc = &ch;//pc是字符指针char*
char arr[] = "abcdef";
char* pc = arr;//字符指针存放数组名
printf("%s\n", arr);
printf("%s\n", pc);//pc指向了字符数组
return 0;
}
int main()
{
const char* p = "abcdef";//"abcdef"是一个常量字符串//p里面存的a的地址,是把字符串的首字符的地址赋给p
printf("%s\n", p);//abcdef
printf("%c\n", *p);//a
return 0;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcdef";
const char* p1 = "abcdef";
const char* p2 = "abcdef";
if (arr1 == arr2)
{
printf("hehe1\n");
}
else
{
printf("haha1\n");
}
//输出haha
//arr1,arr2是首元素地址
if (p1==p2)
{
printf("hehe2\n");
}
else
{
printf("haha2\n");
}
return 0;
//输出hehe
//"abcdef"是常量字符串,在内存里只存了一份,两个指针都指向字符串首地址值
}
是数组,用来存放指针的数组
int main()
{
int arr[10] = { 0 };//整形数组
char arr[5] = { 0 };//字符数组
int* parr[4];//存放整形指针的数组-指针数组
int* ch[10];//存放字符指针的数组-指针数组
return 0;
}
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
int* parr[] = { arr1,arr2,arr3 };//首元素地址
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ",*(parr[i] + j));
//等价于printf("%d",&parr[i][j]);
}
printf("\n");
}
return 0;
}
是指针,指向数组的指针,存放数组的地址
int main()
{
int* p = NULL;//p是整形指针,指向整形的指针-可以存放整形的地址
char* pc = NULL;//pc是字符指针-指向字符的指针-可以存放字符的地址
//数组指针-指向数组的指针-可以存放数组的地址
int arr[10] = { 0 };
//arr-首元素地址
//&arr[0]-首元素的地址
//&arr-数组的地址
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int(*p)[10] = &arr;//p是数组指针,指向数组,数组的类型是int
//int* parr[4]指针数组
return 0;
}
int arr[10];
数组指针一般在二维数组以上使用
//参数是数组的形式
void print1(int arr[3][5], int x, int y)
{
int i = 0;
int j = 0;
for (i = 0; i < x; i++)
{
for (j = 0; j < y; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
//参数是指针的形式
void print2(int(*p)[5], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < y; j++)
{
//printf("%d ", *(*(p + i) + j));
printf("%d ", (*(p + i))[j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
print1(arr,3,5);
printf("\n");
print2(arr, 3, 5);//arr-数组名-数组名就是首元素地址
//二维数组的首元素是第一行
return 0;
}
// int(* parr[10])[5] 是数组,十个元素,每个元素是数组指针(能够指向一个数组,数组5个元素,每个元素是int类型)
//一维数组传参,参数部分可以写成数组,也可以写成指针
int arr[10]={0};
int* arr2[20] = { 0 };
test(arr);
void test(int arr[])
void test(int arr[10])
void test(int *arr)
test2(arr2);
void test2(int* arr2[20])
void test2(int* arr2[])
void test(int **arr)//传的是一级指针的地址
//二维数组的传参
void test(int arr[3][5])
{}
void test(int arr[][5])
{}
void test(int arr[3][])//错的,行可以省略,列不能省略
{}
void test2(int (*arr)[5])
{}
int main()
{
int arr[3][5] = { 0 };
//test(arr);
test2(arr);
return 0;
}
变量的地址和存放地址的一级指针变量
一级指针变量的地址、二级指针变量本身、存放一级指针的数组的数组名
函数指针-指向函数的指针-存放函数地址的指针
int Add(int x, int y)
{
return x + y;
}
int main()
{
//&函数名 和函数名 取出的都是函数的地址
printf("%p\n", &Add);
printf("%p\n", Add);
//int (*pa)(int, int) = &Add;
int (*pa)(int, int) = Add;//Add等价于pa
printf("%d", (*pa)(2, 3));
printf("%d", (*Add)(2, 3));
printf("%d", Add(2, 3));
printf("%d", pa(2, 3));
return 0;
}
void print(char* str)
{
printf("%s", str);
}
int main()
{
char str ;
void(*p)(char*)= print;
(*p)("hello");
return 0;
}
(*(void(*)())0)()
//调用0地址处放的函数,该函数无参,返回类型是void
//(void(*)())0 对0进行强制类型转换,被解释为一个函数地址
//* (void(*)())0 对0地址进行解引用
//(*(void(*)())0)() 调用0地址处的函数
存放同类型的函数指针的数组 取出函数指针数组的地址
指向函数指针数组的指针:是一个指针,指向一个数组,数组的元素都是函数指针
int Add(int x, int y)
{
return x + y;
}
int main()
{
//指针数组
int* arr[10];
//数组指针
int* (*pa)[10] = &arr;
//函数指针
int (*pAdd)(int, int) = Add;
int sum = (*pAdd)(1, 2);
int sum = pAdd(1, 2);
//Add(1,2);
printf("sum=%d\n", sum);
//函数指针的数组
int(*pArr[5])(int, int);
//指向函数指针数组的指针
int(*(*ppArr)[5])(int, int) = &pArr;
return 0;
}
回调函数:通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
头文件
void qsort(void* base, size_t num, size_t size,int (*compar)(const void*, const void*));
第一个参数:待排序数组的首元素地址
第二个参数:待排序数组的元素个数
第三个参数:待排序数组的每个元素的大小-单位是字节
第四个参数:是函数指针,比较两个元素的所用函数的地址-这个函数使用者自己实现
函数指针的两个参数是:待比较的两个元素的地址
void*类型的指针,可以接收任意类型的地址
void*类型的指针,不能进行解引用操作
void*类型的指针,不能进行+-整数的操作
数组名是首元素的地址
1.sizeof(数组名)-数组名表示整个数组
2.&数组名-数组名表示整个数组
//一维数组
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//sizeof(数组名)-计算的是数组的总大小-单位是字节-4*4=16
printf("%d\n", sizeof(a+0));//数组名这里表示首元素地址,a+0还是首元素地址,地址的大小就是4/8字节
printf("%d\n", sizeof(*a));//数组名表示首元素地址,*a就是首元素
printf("%d\n", sizeof(a+1));//数组名这里表示首元素地址,a+1是第二个元素地址,地址的大小就是4/8字节
printf("%d\n", sizeof(a[1]));//第二个元素的大小
printf("%d\n", sizeof(&a));//&a取出的是数组的地址,但是数组的地址也是地址,地址的大小就是4/8个字节
printf("%d\n", sizeof(*&a));//数组的地址解引用是访问的是数组,计算的数组大小,单位是字节
printf("%d\n", sizeof(&a+1));//&a是数组的地址,&a+1虽然地址跳过整个数组,但还是地址,地址的大小
printf("%d\n", sizeof(&a[0]));//第一个元素的地址
printf("%d\n", sizeof(&a[0]+1));//第二个元素的地址
//字符数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));//sizeof计算的是数组的大小,6*1=6字节
printf("%d\n", sizeof(arr+0));//数组名arr这里表示首元素地址,a+0还是首元素地址,地址的大小就是4/8字节
printf("%d\n", sizeof(*arr));//arr是首元素地址,*arr是首元素,char1个字节
printf("%d\n", sizeof(arr[1]));//第二个元素的大小
printf("%d\n", sizeof(&arr));//&arr取出的是数组的地址,但是数组的地址也是地址,地址的大小就是4/8个字节
printf("%d\n", sizeof(&arr+1)); //&arr是数组的地址,& arr + 1虽然地址跳过整个数组,但还是地址,地址的大小
printf("%d\n", sizeof(&arr[0]+1));//第二个元素的地址
printf("%d\n", strlen(arr));//随机值,找\0
printf("%d\n", strlen(arr+0));//随机值
printf("%d\n", strlen(*arr));//err——strlen要的是地址,*arr相当于是首元素,崩溃了
printf("%d\n", strlen(arr[1]));//err——strlen要的是地址,第二个元素,崩溃了
printf("%d\n", strlen(&arr));//随机值
printf("%d\n", strlen(&arr+1));//随机值
printf("%d\n", strlen(&arr[0]+1));//随机值
char arr[] = "abcdef";//数组里面放的是a,b,c,d,e,f,\0
printf("%d\n", sizeof(arr));//7,sizeof(arr)计算的数组的大小,单位是字节
printf("%d\n", sizeof(arr + 0));//4,计算的是首元素地址的大小,arr+0是首元素的地址
printf("%d\n", sizeof(*arr));//1,*arr是首元素,计算首元素的大小
printf("%d\n", sizeof(arr[1]));//1,第二个元素
printf("%d\n", sizeof(&arr));//4,数组的地址
printf("%d\n", sizeof(&arr + 1));// 4,跳过整个数组后的地址
printf("%d\n", sizeof(&arr[0] + 1));//4,第二个元素的地址
printf("%d\n", strlen(arr));//6,首元素地址
printf("%d\n", strlen(arr + 0));//6,首元素地址
//printf("%d\n", strlen(*arr));//err——strlen要的是地址,*arr相当于是首元素,崩溃了
//printf("%d\n", strlen(arr[1]));//err——strlen要的是地址,第二个元素,崩溃了
//printf("%d\n", strlen(&arr));//err——&arr类型为数组的地址——数组指针char (*)[7],strlen参数类型const char *
//printf("%d\n", strlen(&arr+1));//err——下个数组的地址
printf("%d\n", strlen(&arr[0] + 1));//5,第二个元素开始向后数
const char* p = "abcdef";//把常量字符串a的地址放在p中
printf("%d\n", sizeof(p)); // 4,p是首元素的地址,是指针变量-计算指针变量p的大小
printf("%d\n", sizeof(p + 1)); // 4,p+1是第二个元素字符b的地址,是指针
printf("%d\n", sizeof(*p)); // 1,指针解引用等于字符串的第一个字符
printf("%d\n", sizeof(p[0]));//1,p[0]=a
printf("%d\n", sizeof(&p)); // 4,二级指针,是地址
printf("%d\n", sizeof(&p + 1));// 4,跳过p,还是地址
printf("%d\n", sizeof(&p[0] + 1));//4,第二个元素b的地址
printf("%d\n", strlen(p));//6,从a往后数
printf("%d\n", strlen(p + 1));// 5,从b往后数
//printf("%d\n", strlen(*p)); // 编译报错
//printf("%d\n", strlen(p[0])); // 编译报错
//printf("%d\n", strlen(&p)); // 随机值
//printf("%d\n", strlen(&p + 1)); // 随机值
printf("%d\n", strlen(&p[0] + 1));// 5,从第二个元素往后数
//二维数组
int a[3][4] = { 0 }; //注意:二维数组,也可以看作一维数组,只不过数组里面放的元素是数组
printf("%d\n", sizeof(a)); // 48 数组总大小12*4=48
printf("%d\n", sizeof(a[0][0]));// 4 a[0][0]一行一列的元素,数组中首位元素
printf("%d\n", sizeof(a[0]));// 16 a[0]相当于第一行作为一维数组的数组名,把数组名单独放在sizeof()内,计算的是第一行的大小 4*4
printf("%d\n", sizeof(a[0] + 1));// 4 a[0]是第一行的数组名,数组名此时是(首元素)第一行第一个元素的地址,+1 代表第一行第二个元素地址
printf("%d\n", sizeof(*(a[0] + 1)));//4 同上 ,只不过对上面进行解引用,是第一行第二个元素 大小为4
printf("%d\n", sizeof(a + 1)); //4 a是二维数组的数组名,没有sizeof(数组名),也没有&(数组名),所以a是首元素地址
//二维数组的首元素是第一行,a就是第一行(首元素)的地址,a+1代表数组中第二行一维数组的地址,大小为4
printf("%d\n", sizeof(*(a + 1)));//16 *(a+1)) 解引用代表数组中第二个“元素”,计算第二行的大小,4*4
printf("%d\n", sizeof(&a[0] + 1));//4 第二行的地址,大小为4
printf("%d\n", sizeof(*(&a[0] + 1)));//16 第二行元素4*4
printf("%d\n", sizeof(*a)); //16 a是二维数组的首元素地址,*a是第一行 4*4
printf("%d\n", sizeof(a[3])); //16 越界访问,但能算出长度为16(sizeof内部表达式不参与计算)
char** cpp;
cpp[-2][-1]==>*(*(cpp-2)-1)
//杨氏矩阵:有一个二维数组. 数组的每行从左到右是递增的,每列从上到下是递增的. 在这样的数组中查找一个数字是否存在。 时间复杂度小于O(n)
int FindNum(int arr[3][3], int k, int row, int col)
{
int x = 0;
int y = col - 1;
while (x <= row - 1 && y >= 0)
{
if (arr[x][y] > k)
{
y--;//当前数组右上角元素大于要找元素时,一定不在第一行,删掉一行
}
else if (arr[x][y] < k)
{
x++; //当前数组右上角元素小于要找元素时,一定不在最右边一列,删掉一列
}
else
{
return 1;
}
}
return 0;//找不到
}
//实现一个函数,可以左旋字符串的k个字符
暴力求解法
#include
#include
void left_move(char* arr,int k)
{
assert(arr);
int i = 0;
int len = strlen(arr);
for (i = 0; i < k; i++)
{
//左旋转一个字符
char tmp = *arr;
int j = 0;
for (j = 0; j < len - 1; j++)
{
*(arr + j) = *(arr + j + 1);
}
*(arr + len - 1) = tmp;
}
}
int main()
{
char arr[] = "abcdef";
left_move(arr, 2);
printf("%s\n", arr);
return 0;
}
三部翻转法
void reverse(char* left, char* right)
{
assert(left != NULL);
assert(right != NULL);
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
void left_move(char* arr, int k)
{
assert(arr);
int len = strlen(arr);
assert(k <= len);
reverse(arr,arr+k-1);//逆序左边
reverse(arr+k,arr+len-1);//逆序右边
reverse(arr,arr+len-1);//逆序整体
}
int main()
{
char arr[] = "abcdef";
left_move(arr, 2);
printf("%s\n", arr);
}
//写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串
int is_left_move(char* s1, char* s2)
{
int len = strlen(s1);
int i = 0;
for (i = 0; i < len; i++)
{
left_move(s1, i);
int ret=strcmp(s1, s2);
if (ret == 0)
return 1;
}
return 0;
}
也可以在str1后面追加str1,然后判断str2是否为子串
int is_left_move(char* str1, char* str2)
{
int len1 = strlen(str1);
int len2 = strlen(str2);
if (len1 != len2)//两串长度不一样时,提前返回0
return 0;
strncat(str1, str1, 6);//在str1字符串中追加一个str1字符串
char* ret=strstr(str1, str2);//找子串
if (ret == NULL)
{
return 0;
}
else
{
return 1;
}
}
//指针函数逆序字符串
#include
#include
void reverse(char* str)
{
assert(str);
int len = strlen(str);
char* left = str;
char* right = str + len - 1;
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main()
{
char arr[256] = { 0 };
//scanf("%s", arr);
gets_s(arr);//录入一行
reverse(arr);//逆序
printf("%s\n", arr);
return 0;
}
//求Sn=a+aa+aaa+aaaa+aaaaa的前n项之和,其中a是一个数字
int Sum(int a,int n)
{
int sum = 0;
int i = 0;
int ret=0;
for (i = 0; i
//求自幂数:如果在一个固定的进制中,一个n位自然数等于自身各个数位上数字的n次幂之和,则称此数为自幂数。(n=3时,为水仙花数)
#include
int main()
{
int i = 0;
for (i = 0; i <= 1000000; i++)
{
//1.计算i的位数
int n = 1;
int tmp = i;
int sum = 0;
while (tmp/=10)
{
n++;
}
//2.计算i的每一位的n次方之和sum
tmp = i;
while (tmp)
{
sum += pow(tmp % 10, n);
tmp /= 10;
}
//3.比较i和sum
if (i == sum)
{
printf("%d ", i);
}
}
return 0;
}
//打印n行菱形
*
***
*****
*******
*****
***
*
int main()
{
int line = 0;
scanf("%d", &line);//只有总行数为奇数时可以打印,输入上半部分行数
//打印上半部分
int i = 0;
for (i = 0; i < line; i++)
{
//打印空格
int j = 0;
for (j = 0; j
//喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以喝多少汽水
int main()
{
int money = 0;
int total = 0;
int empty = 0;
scanf("%d", &money);
//买回来的汽水喝掉
total = money;
empty = money;
//换回来的汽水
while (empty >= 2)
{
total += empty / 2;
empty=empty / 2 + empty % 2;
}
printf("%d", total);
}
//调整数组使奇数全部都位于偶数前面
//从左边开始找偶数,从右边开始找奇数,把他们交换
void move(int arr[], int sz)
{
int left = 0;
int right = sz - 1;
while (left < right)
{
while ((left < right)&&(arr[left] % 2 == 1))
{
left++;
}
while ((left < right)&&(arr[right] % 2 == 0))
{
right--;
}
if (left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}
}
}
//打印杨辉三角
int main()
{
int arr[10][10] = { 0 };
int i = 0;
int j = 0;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (j == 0)
{
arr[i][j] = 1;
}
if (i==j)
{
arr[i][j] = 1;
}
if((i>=2)&&(j>=1)&&(j!=i))
arr[i][j] = arr[i-1][j-1] + arr[i-1][j];
}
}
for (int i = 0; i < 10; i++)
{
for (int j = 0; j <=i; j++)
{
printf("%3d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
//逻辑推理:判断凶手是谁问题
int main()
{
int killer = 0;
for (killer = 'a'; killer <= 'd'; killer++)
{
if ((killer != 'a') + (killer == 'c') + (killer == 'd') + (killer != 'd') == 3)
{
printf("killer=%c\n", killer);
}
}
return 0;
}