C语言知识点笔记8
此笔记是我考研备考专业课期间听课的一些C语言知识点混记,可能会有一点乱,有需要的朋友们可以翻阅一下,有利于巩固C语言知识点!
1、函数实现功能:
实现函数init() 初始化数组全为0
实现print() 打印数组的每一个元素
实现reverse() 函数完成数组元素的逆置
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,10};
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr, sz);
reverse(arr, sz);
print(arr, sz);
init(arr, sz);
print(arr, sz);
return 0;
}
2、指针系列:
(1)指针的大小在32位平台是4个字节,在64位平台是8个字节
int main()
{
int* pa;
char* pc;
float* pf;
printf("%d\n", sizeof(pa));
printf("%d\n", sizeof(pc));
printf("%d\n", sizeof(pf));
//结果全为4
}
(2)指针类型的意义:
1、指针类型决定了:指针解引用的权限有多大
2、指针类型决定了,指针走一步,能走多远(步长)
(3)野指针:
指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
int main()
{
1.未初始化
//这里的p就是一个野指针
int* p;//p是一个局部的指针变量,局部变量不初始化的话,默认值是随机值
*p = 20;//非法访问内存了
2、越界访问
int arr[10] = {0};
int* p = arr;
int i = 0;
for(i = 0;i <= 10; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*p = i;
p++;
}
}
当前不知道p应该初始化为什么地址的时候,直接初始化为NULL
(int p = NULL;)*
如何规避野指针:
1、指针初始化
2、小心指针越界
3、指针指向空间释放及时置NULL
4、指针使用之前检查有效性
(4)指针减去指针
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
printf("%d\n", &arr[9] - &arr[0]); //输出为9
//指针减去指针得到的是两个指针之间的元素个数
//指针和指针相减的前提:两个指针指向同一块空间
return 0;
}
(5)二级指针
int main()
{
int a = 10;
int* pa = &a;//pa是指针变量,一级指针
//ppa就是一个二级指针变量
int* *ppa = &pa;//pa也是个变量,&pa取出pa在内存中起始地址
int** *pppa = &ppa;
}
(6)指针数组
int main()
{
int arr[10];//整型数组-存放整型的数组就是整型数组
char ch[5];//字符数组-存放的是字符
//指针数组-存放指针的数组
int* parr[5];//整型指针的数组
char* pch[5];//字符指针的数组
return 0;
}
3、结构体:
struct B
{
char c;
short s;
double d;
};
struct Stu
{
//成员变量
struct B sb;
char name[20];//名字
int age;//年龄
char id[20];
} s1,s2;//s1和s2也是结构体变量
//s1,s2是全局变量
void print1(struct Stu t)
{
printf("%c %d %lf %s %d %s\n", t.sb.c, t.sb.s, t.sb.d, t.name, t.age, t.id);// 输出w 20 3.140000 张三 30 20201220
}
void print2(struct Stu* ps)
{
printf("%c %d %lf %s %d %s\n", ps->sb.c, ps->sb.s, ps->sb.d, ps->name, ps->age, ps->id);// 输出w 20 3.140000 张三 30 20201220
}
int main()
{
//s是局部变量
struct Stu s = {{'w', 20, 3.14}, "张三", 30, "20201220"};//对象
//. ->
printf("%c\n", s.sb.c);//输出w
printf("%s\n", s.id);//输出20201220
struct Stu* ps = &s;
printf("%c\n", (*ps).sb.c);//输出w
printf("%c\n", ps->sb.c);//输出w
//写一个函数打印s的内容
print1(s); 传值调用
print2(&s); 传址调用
//使用首选print2函数:因为函数传参的时候,参数是需要压栈的。如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降
结论:结构体传参的时候,要传结构体的地址
return 0;
}
4、模拟strcpy函数
#include <stdio.h>
#include <assert.h>
//把src指向的内容拷贝放进dest指向的空间中
//从本质上讲,希望dest指向的内容被修改,src指向的内容不应该被修改
char* my_strcpy(char* dest, const char* src)//加完const,src的内容不被修改
{
assert(src != NULL);//断言
assert(dest != NULL);//断言
char* ret = dest;
while (*dest++ = *src++) //既copy了\0,又使得循环停止。\0的ascll码为0
{
;//hello的拷贝
}
return ret;//返回目标空间的起始地址
}
int main()
{
char arr1[20] = "xxxxxxxxx";
char arr2[] = "hello";
//strcpy(arr1, arr2); 1、目标空间的起始地址 2、源空间的起始地址
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
5、模拟strlen函数 求字符串长度
#include <assert.h>
size_t my_strlen(const char* str)//size_t--unsigned int无符号整型
{
//assert(str != NULL);
assert(str);
size_t count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abc";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}