calloc
测试代码(free之前先判断,这一点挺好)
#include<stdio.h>
#include<stdlib.h>
void test() {
int *p = (int*)calloc(10, sizeof(int));
for (int i = 0; i < 10; ++i) {
p[i] = i + 1;
}
for (int i = 0; i < 10; ++i) {
printf("%d", p[i]);
}
if (p != NULL) {
free(p);
p = NULL;
}
}
运行结果
不同平台下 size_t 可能是不同的,不一定是unsigned int
realloc
作用
1、在原有空间的后面继续扩展内存
2、如果申请失败,则将源数据挪走到新申请的连续整块内存中。并将原数据占的内存清理
测试代码如下:
#include<stdio.h>
#include<stdlib.h>
void test() {
int *p = (int*)malloc(sizeof(int)*10);
for (int i = 0; i < 10; ++i) {
p[i] = i + 1;
}
for (int i = 0; i < 10; ++i) {
printf("%d", p[i]);
}
printf("\n");
printf("%d\n", p);
p = (int*)realloc(p, sizeof(int) * 1000);
printf("%d\n", p);
for (int i = 0; i < 10; ++i) {
printf("%d", p[i]);
}
if (p != nullptr) {
free(p);
p = nullptr;
}
}
int main() {
test();
return 0;
}
运行结果
sscanf
1、跳过数据
#include<stdio.h>
#include<stdlib.h>
//%*s或%*d 跳过数据
void test01() {
#if 0
char *str = "12345abcde";
char buf[1024] = { 0 };
sscanf(str, "%*d%s", buf);
printf("buf:%s\n", buf);
#else
const char *str = "abcde 12345";
char buf[1024] = { 0 };
sscanf(str, "%*s%s", buf);
printf("buf:%s\n", buf);
#endif
}
注意:如果else里面的str是“abcde12345”,则得到的结果是,因为要有边界
忽略字符串到空格或者\t
运行结果
2、%[width]s 读取指定宽度的数据
#include<stdio.h>
#include<stdlib.h>
void test01() {
char *str = "12345abcde";
char buf[1024] = { 0 };
sscanf(str, "%5s", buf);
printf("buf:%s\n", buf);
}
int main() {
test01();
return 0;
}
运行结果
3、%[a-z] 匹配a到z中任意字符(尽可能多匹配)
注意:他会从第一个元素开始匹配,如果匹配不上,则直接退出,哪怕你后面的元素匹配的上。
#include<stdio.h>
#include<stdlib.h>
void test01() {
char *str = "abcde12345";
char buf[1024] = { 0 };
sscanf(str, "[a-z]", buf);
printf("buf:%s\n", buf);
}
int main() {
test01();
return 0;
}
运行结果
如果把"abcde12345"改成"12345abcde",则运行结果会变成:
可以把条件改成%*d%[a-z],这样就能匹配到abcde了
4、%[aBc] 匹配a、B、c中的一员,贪婪性
#include<stdio.h>
#include<stdlib.h>
void test01() {
const char *str = "aABbcde";
char buf[1024] = { 0 };
sscanf(str, "%[aAb]", buf);
printf("buf:%s\n", buf);
}
int main() {
test01();
return 0;
}
运行结果:
5、%[^c] 匹配非c的任意字符,贪婪性 遇到c就退出
#include<stdio.h>
#include<stdlib.h>
void test01() {
const char *str = "aABbcde";
char buf[1024] = { 0 };
sscanf(str, "%[^c]", buf);
printf("buf:%s\n", buf);
}
int main() {
test01();
return 0;
}
运行结果:
6、%[^a-z] 表示取a-z之外的所有字符 遇到就退出
#include<stdio.h>
#include<stdlib.h>
void test01() {
const char *str = "12345aABbcde";
char buf[1024] = { 0 };
sscanf(str, "%[^a-z]", buf);
printf("buf:%s\n", buf);
}
int main() {
test01();
return 0;
}
运行结果
实例:ip地址匹配
#include<stdio.h>
#include<stdlib.h>
void test01() {
const char *ip= "127.0.0.1";
int num1 = 0, num2 = 0, num3 = 0, num4 = 0;
sscanf(ip, "%d.%d.%d.%d", &num1 , &num2, &num3, &num4);
printf("num1:%d\n", num1);
printf("num2:%d\n", num2);
printf("num3:%d\n", num3);
printf("num4:%d\n", num4);
}
int main() {
test01();
return 0;
}
运行结果:
实例2
#include<stdio.h>
#include<stdlib.h>
void test01() {
const char *str="abcde#12uiop@0p1ju";
char buf[1024]={0};
sscanf(str, "%*[^#]#%[^@]", buf);
printf("buf:%s\n", buf);
}
int main() {
test01();
return 0;
}
运行结果
查找子串 strstr
我面滴滴的时候被问过怎么写这个
#include<stdio.h>
#include<stdlib.h>
char* myStrStr(const char* str, const char* sub){
const char* father=str;
const char* f=NULL;
const char* son=sub;
const char* s=NULL;
while(*father!='\0'){
if(*father==*son){
f=father;
s=son;
while(*f==*s){
f++;
s++;
}
if(*s=='\0'){
return father;
}
}
father++;
}
return NULL;
}
void test(){
char *str="abcdefghi0";
char *sub="ghi";
char *res=myStrStr(str, sub);
printf("res=%s\n",res);
}
int main() {
test();
return 0;
}
指针易错点
1、指针越界
#include<stdio.h>
#include<stdlib.h>
void test() {
const char buf[3] = "abc";
printf("buf=%s\n", buf);
}
int main() {
test();
return 0;
}
2、指针叠加会改变指针指向
char*p = (char*)malloc(64);
++p;
if (p != NULL) {
free(p);
p = NULL;
}
3、返回局部变量地址
char* test() {
char str[] = "abcdefg";
return str;
}
4、同一块内存释放多次
const使用
在使用对象指针的时候,有可能意外的修改数据。使用const可以规避地址传递的副作用。
#include<stdio.h>
#include<stdlib.h>
struct Person {
char name[64];
int age;
int ID;
double score;
};
void Print(const struct Person *person) {
printf("name=%s age=%d ID=%d score=%f\n",
person->name, person->age, person->ID, person->score);
}
void test() {
struct Person person = { "Trump", 30, 250, 59.9 };
Print(&person);
}
int main() {
test();
return 0;
}
不过加了const也可以改
void Print(const struct Person *person) {
//强制类型转换
struct Person *p = (struct Person *)person;
p->ID = 1299;
printf("name=%s age=%d ID=%d score=%f\n",
person->name, person->age, person->ID, person->score);
}
二级指针练习文件读写
要求:文件有多少空间就申请多少空间
第一版本——读取文件行数,开辟相应大小的内存空间。将每一行都存入buf中
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//获得文件行数
int getFileLines(FILE *file){
if(file==NULL) return -1;
//按行读取 fgets();
char buf[1024]={0};
//记录读取了几行文件
int lines=0;
while(fgets(buf, 1024, file)!=NULL){
lines++;
}
//恢复文件指针指向文件起始位置
//否则下次读取文件内容的时候就是直接读指针后面的东西了
//然而此时指针已经指向了文件末尾
fseek(file, 0, SEEK_SET);
return lines;
}
//读取文件行数
void readFileData(FILE *file, int lines, char **contents){
if((file==NULL)||(contents==NULL)||(lines<=0))
return;
//创建缓冲区
char buf[1024]={0};
while(fgets(buf, 1024, file)!=NULL){
printf("nuf=%s\n",buf);
memset(buf, 0, 1024);
}
}
void test(){
//打开文件
FILE *file=fopen("./file.txt", "r");
if(file==NULL){
printf("打开文件失败");
return;
}
//统计文件行数
int lines=getFileLines(file);
printf("lines=%d\n",lines);
//开辟空间
char **pContents=malloc(sizeof(char*)* lines);
readFileData(file, lines, pContents);
}
int main() {
test();
return 0;
}
运行结果:
第二版——将每一行数据读取出来并申请相应大小的内存。最后将数据打印出来
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//获得文件行数
int getFileLines(FILE *file){
if(file==NULL) return -1;
//按行读取 fgets();
char buf[1024]={0};
//记录读取了几行文件
int lines=0;
while(fgets(buf, 1024, file)!=NULL){
lines++;
}
//恢复文件指针指向文件起始位置
//否则下次读取文件内容的时候就是直接读指针后面的东西了
//然而此时指针已经指向了文件末尾
fseek(file, 0, SEEK_SET);
return lines;
}
//读取文件行数
void readFileData(FILE *file, int lines, char **contents){
if((file==NULL)||(contents==NULL)||(lines<=0))
return;
//创建缓冲区
char buf[1024]={0};
int index=0;
while(fgets(buf, 1024, file)!=NULL){
//printf("nuf=%s\n",buf);
//获取当前行的长度 +1是为了'\0'
int curLineLen=strlen(buf)+1;
//给当前行分配内存
char* lineContent=malloc(sizeof(char)*curLineLen);
//将行数据拷贝到空间中
strcpy(lineContent, buf);
contents[index++]=lineContent;
memset(buf, 0, 1024);
}
}
//打印文件内容
void showFileContents(char **contents, int lines){
for(int i=0; i<lines; i++){
printf("%d行%s:",i+1,contents[i]);
}
}
void test(){
//打开文件
FILE *file=fopen("./file.txt", "r");
if(file==NULL){
printf("打开文件失败");
return;
}
//统计文件行数
int lines=getFileLines(file);
printf("lines=%d\n",lines);
//开辟空间
char **pContents=malloc(sizeof(char*)* lines);
//读取文件内容
readFileData(file, lines, pContents);
//打印文件内容
showFileContents(pContents, lines);
}
int main() {
test();
return 0;
}
运行结果:
第三版(完整版)——释放内存
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//获得文件行数
int getFileLines(FILE *file){
if(file==NULL) return -1;
//按行读取 fgets();
char buf[1024]={0};
//记录读取了几行文件
int lines=0;
while(fgets(buf, 1024, file)!=NULL){
lines++;
}
//恢复文件指针指向文件起始位置
//否则下次读取文件内容的时候就是直接读指针后面的东西了
//然而此时指针已经指向了文件末尾
fseek(file, 0, SEEK_SET);
return lines;
}
//读取文件行数
void readFileData(FILE *file, int lines, char **contents){
if((file==NULL)||(contents==NULL)||(lines<=0))
return;
//创建缓冲区
char buf[1024]={0};
int index=0;
while(fgets(buf, 1024, file)!=NULL){
//printf("nuf=%s\n",buf);
//获取当前行的长度 +1是为了'\0'
int curLineLen=strlen(buf)+1;
//给当前行分配内存
char* lineContent=malloc(sizeof(char)*curLineLen);
//将行数据拷贝到空间中
strcpy(lineContent, buf);
contents[index++]=lineContent;
memset(buf, 0, 1024);
}
}
//打印文件内容
void showFileContents(char **contents, int lines){
for(int i=0; i<lines; i++){
printf("%d行%s:",i+1,contents[i]);
}
}
//释放内存
void freeFileSpace(char ** contents, int lines){
for(int i=0; i<lines; i++){
if(contents[i]!=NULL){
free(contents[i]);
contents[i]=NULL;
}
}
if(contents!=NULL){
free(contents);
contents=NULL;
}
}
void test(){
//打开文件
FILE *file=fopen("./file.txt", "r");
if(file==NULL){
printf("打开文件失败");
return;
}
//统计文件行数
int lines=getFileLines(file);
printf("lines=%d\n",lines);
//开辟空间
char **pContents=malloc(sizeof(char*)* lines);
//读取文件内容
readFileData(file, lines, pContents);
//关闭文件
fclose(file);
file=NULL;
//打印文件内容
showFileContents(pContents, lines);
//释放文件数据
freeFileSpace(pContents, lines);
}
int main() {
test();
return 0;
}
运行结果:
位运算
位逻辑运算符
按位取反~
#include<stdio.h>
#include<stdlib.h>
void test() {
//2 的二进制是010 按位取反为101
//负数使用补码存储 补码的计算方式是除了最高位,其余的按位取反然后再加1
//因此101的补码为 110+1=111
int number = 2;
printf("~number:%d\n", ~number);
}
int main() {
test();
return 0;
}
运行结果:
位与(AND):&
可以判断指定位置是否为0
可用于判断某一位上是0还是1(计算快速幂的时候需要判断幂次的二进制形式的每一位都是什么)
也可以用这个判断一个数的奇偶性
注意:&的优先级小于“==”
#include<stdio.h>
#include<stdlib.h>
void test() {
int number = 332;
if ((number & 1 )== 0) {
printf("%d是偶数\n", number);
}
else {
printf("%d是奇数\n", number);
}
}
int main() {
test();
return 0;
}
number = number & 0;
等价于
number &=0;
位或(OR):|
可以判断指定位置是否为1
#include<stdio.h>
#include<stdlib.h>
void test() {
int num1 = 5;
int num2 = 3;
printf("num1 | num2 = %d\n", num1 | num2);
}
int main() {
test();
return 0;
}
运行结果:
位异或
同则 0 ,不同则 1
交换两个数字的值的例子
#include<stdio.h>
#include<stdlib.h>
void test() {
int num1 = 5;
int num2 = 3;
num1 = num1 ^ num2;
num2 = num1 ^ num2;
num1 = num1 ^ num2;
printf("num1 =%d num2 = %d\n", num1 , num2);
}
int main() {
test();
return 0;
}
运行结果:
移位运算符
左移——相当于乘以2的n次幂
001<<1 变成 010