C基础学习笔记01

LinuxC基础学习(知识点)_01
  • 野指针的产生与解决
#include <stdio.h>
#include <stdlib.h>

int main()
{

    char * p = NULL;//初始化p = NULL,即p->0x0000
    p = (char *)malloc(100);//为p分配内存,p->0x1234

     strcpy(p,"hello world");
     //操作系统为"hello world"分配内存,并将"hello world"复制到p指向的内存空间
     // p->0x1234
     // *p -> "hello world"

     if (p != NULL){ //此时p->0x1234不为空
        free(p);//产生野指针
        //free(p) 使p 指向的内存为空, 即 *p = NULL,也就是将"hello world"->NULL,但是p仍旧指向0x1234
//解决方案:p = NULL;//置空解决野指针的产生问题
     }

    if (p != NULL)//当p没有置空的时候,p->0x1234不为空, *p 里面的内容为空
    {
            free(p);//回收p,即free(NULL);会引发中断
    }

    printf("Hello world!\n");
    return 0;
}
当分配内存回收的时候,记得置空[free(p),p = NULL]
  • 不要向[NULL]写入数据
#include <stdio.h>
#include <stdlib.h>

int main (){

  char * p = NULL; //初始化内存

//解决方案: p = (char *)malloc(100); //为p分配内存空间

  strcpy(p,"hello world"); // NULL -> 0x0000 即 p->0x0000这段内存空间,这段内存空间是操作系统大哥//所使用的,不能写入。

  return 0;
}
 char * p = (char *)malloc(100);//当需要自己手动分配内存的时候,可以在初始化的时候顺便分配内存。
  • 一个指针可以指向多个不同的内存
#include <stdio.h>
#include <stdlib.h>
int main(){
  char * p = NULL;
  char buf[128] = "hello";
  char * temp = (char *)malloc(100);
  strcpy(temp,"world");
  p = buf;//合法
  p = temp;//合法
  return 0;
}
  同一个指针可以操作不同地址的内存,C语言和Java语言的区别
  • 指针间接赋值技术
#include <stdio.h>
#include <stdlib.h>

int change(int num){
  num = 30;
  return num;
}

void changep(int * num)
{
  *num = 100;
}

int main (){


  //1.在同意作用域利用p间接改变num的值
  int num = 10;
  int * p = &num;
  *p = 20;
  //===============

  //2.利用函数的返回值,但是return 每次只能返回一个数,即使返回 struct 也不方便
  num = change(num);  
  //==============

  //3.利用指针传递地址
  changep(&num);
  //=============

  return 0;
}
  • 二级指针
#include <stdio.h>
#include <stdlib.h>

void changep(char ** temp){
  *temp = 0x300;
}

int main(){

  char *temp_1 = NULL;
  char ** temp_2 = NULL;

  temp_1 = 0x111;
  temp_2 = 0x222;

  //直接修改temp_1的值
  temp_1 = 0x1122;

  //间接修改temp_1的值
  temp_2 = &temp_1;
  //temp_2存储的temp_1的地址
  //*temp_2 ==> temp_1的地址
  //**temp_2 ==> *temp ==> 拿到一个内存地址的值

  *temp_2 = 0x100;//将temp_1的地址指向0x100

  printf("temp_1:%p\n",temp_1);

  //在函数外部改变temp_1的地址
  changep(&temp_1);

  printf("temp_1:%p\n",temp_1);

}
修改一个变量的地址需要一级指针;修改一个一级指针的地址需要二级指针
  • 指针间接赋值,C语言接口设计思想
//指针间接赋值
//接口封装设计

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//函数声明[返回值判断此函数块的运行状态是否正常]
int Interface(char ** temp_1,int * temp_1_len,char ** temp_2,int * temp_2_len);
void Freestr(char ** temp_1,char ** temp_2);

int main()
{


    char * one = NULL;
    char * two = NULL;
    int len_1 = 0;
    int len_2 = 0;

    int type = Interface(&one,&len_1,&two,&len_2);

    if (type == 0){
        printf(" application is error!\n");
        return type;
    }

    printf("one->%s || %d\n",one,len_1);
    printf("two->%s || %d\n",two,len_2);

    //回收内存
    Freestr(&one,&two); 

    return 0;
}

int Interface(char ** temp_1/*out*/,int * temp_1_len/*out*/,char ** temp_2/*out*/,int * temp_2_len/*out*/){

    char * t_one = (char *)malloc(1024);
    char * t_two = (char *)malloc(1024);

    if (t_one == NULL || t_two == NULL)
            return 0;
    //application run error!

    /*================
    处理分配的内存
    ================*/
    strcpy(t_one,"This is temp_1 memery is run ");
    strcpy(t_two,"This is temp_two memery is tun too ");

    int one_length = strlen(t_one);
    int two_length = strlen(t_two);

    //指针间接赋值
    *temp_1 = t_one;
    *temp_2 = t_two;

    *temp_1_len = one_length;
    *temp_2_len = two_length;

    return 1;

}
//释放内存
void Freestr(char ** temp_1/*in*/,char ** temp_2/*in*/){

    if (*temp_1 == NULL) return ;
    free(*temp_1);
    *temp_1 = NULL;
    if (*temp_2 == NULL) return ;
    free(*temp_2);
    *temp_2 = NULL;
}
  • 一级指针的用法[数组|字符串]
char str[] = {'a','b','c','d'};//代表一个数组,并不是一个字符串
char string = "hello world";//作为字符数组,占用12个字节,作为字符串,占用11个字节
int len = strlen(string);//计算字符串的长度
int size = sizeof(string);//计算数组的大小

//打印字符串string
//1.
int i = 0;
for (i = 0;i < strlen(string);i++){
  printf("%c",string[i]);
} 
printf("\n");
//2.
char * p = NULL;
p = string;//拿到字符串元素的首地址
for (i = 0;i < strlen(string);i++){
  printf("%c",*(p+i));
}
printf("\n");
  • 指针和内存的首地址区别
char str[] = "abcd";
str = 0x1234;//错误,str是一个常量,不可被更改
int * p = NULL;//指针是一个变量,可以被更改
p = 0x1234;//允许
p = 0x1122;//允许
  • 字符串的内存分布
char str[20] = "abcd";//栈区,可读可写,占用20个字节,由系统自动回收
char str2[] = "abcd";//栈区,可读可写,占用5个字节,由系统自动回收
char * pstr1 = "abcd";//代码区,可读不可写,占用4个字节,由系统自动回收
char * pstr2 = (char *)malloc(100);//堆区,可读可写,占用100个字节,由程序员手动回收
strcpy(pstr2,"abcd");
  • 字符串strcpy手动实现及优化
void str_copy(char * from,char * to){

    /*1.==========================
    for (;*from != '\0';from++,to++) *to = *from;
    *to = '\0';
    ===========================*/

    /*2.==========================
    for (;*from != '\0';) *to++ = *from++;
    *to = '\0';
    ===========================*/

    /*3.==========================
    while (*from != '\0'){
        from++;
        to++;
    }
    *to = '\0';
    ===========================*/

    /*4.==========================
    while ((*from = *to) != '\0' ){
        from++;
        to++;
    }
    ===========================*/

    /*5.==========================
    while ((*to++ = *from++) != '\0');
    ===========================*/

    /*6.==========================
    while ((*to++ = *from++));
    ===========================*/
    return ;
}
  • 在母串中查找子串出现的次数
int getstrcount(char * str/*in*/,char * sub/*in*/,int * count/*out*/){
    //记录出现的次数
    int tempcount = 0;
    //不要轻易去改变形参的值
    char * temp = str;
    if (str == NULL || sub == NULL || count == NULL)
        return -1;
    while (temp = strstr(temp,sub)){
        printf("%s\n",temp);
        tempcount++;
        temp += strlen(sub);
        if (*temp == '\0') break;
    }
    *count = tempcount;
    return 0;
}
  • 字符串两头堵模型[计算非空字符串的长度|字符串去空格]
/*去掉字符串的空格*/
int LeftandRightTrimSpaceInterface(char * str/*in*/,char * buf/*out*/){

    if (str == NULL || buf == NULL)
        return -1;

    int start = 0;
    int end = strlen(str) - 1;

    while (isspace(str[start]) && str[start] != '\0') start++;
    while (isspace(str[end]) && str[end] != '\0') end++;

    strncpy(buf,str+start,end-start+1);

    return 0;
}
/*计算非空字符串的长度*/
int LeftandRightCountSpaceInterface(char * str/*in*/,int * count/*out*/){

    if (str == NULL || count == NULL)
        return -1;

    int start = 0;
    int end = strlen(str) - 1;

    while (isspace(str[start]) && str[start] != '\0') start++;
    while (isspace(str[end]) && str[end] != '\0') end--;

    *count = end - start + 1;

    return 0;
}
  • 字符串反转
/**
    函数在调用前应该先初始化用作输出的字符串[memset(string,0,sizeof(string));]
**/
/*1.========================================================================
int inreverse(char * str/*in*/){
    if (str == NULL)
        return -1;
    int start = 0;
    int end = strlen(str) - 1;
    for (;start < end;start++,end--){
        char temp = str[start];
        str[start] = str[end];
        str[end] = temp;
    }
    return 0;
}
========================================================================*/
/*2========================================================================
void inreverse_2(char * str /*in*/,char * string /*out*/){
    if (str == NULL ||string = NULL ||  *str == '\0'){
        *(string + strlen(string) + 1) = '\0';
         return ;
    }
    *(string + strlen(str) - 1) = *str;
    inreverse_2(str+1,string);
}
========================================================================*/
/*3========================================================================
void inreverse_3(char * str/*in*/,char * string/*out*/){
    if (str == NULL || string == NULL || *str == '\0'){
        return ;
    }
    inreverse_3(str+1,string);
    printf("str = %c\n",*str);
    strncat(string,str,1);
}
========================================================================*/
  • 根据key解析value的值案例
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

int getKeyByValue(char * str,char * key,char * value);
int getStringTrimSpace(char * str,char * value);

int main()
{
    char value[20] = {0};
    char * str = "name = xiaoming";
    getKeyByValue(str,"name",value);
    printf("value = %s\n",value);
    return 0;
}

//根据key解析value
int getKeyByValue(char * str/*in*/,char * key/*in*/,char * value/*out*/){

    char * pstr = NULL;//临时指针变量

    if (str == NULL || key == NULL || value == NULL)
        return -1;

    //查找key是否在str中
    pstr = str;
    pstr = strstr(pstr,key);
    if (pstr == NULL)
        return -1;
    pstr = pstr + strlen(key);

    //查找等号的位置
    pstr = strstr(pstr,"=");
    if (pstr == NULL)
        return -1;
    pstr = pstr + strlen("=");

    //去除value左右两边的空格
    int type =getStringTrimSpace(pstr,value);
    if (type == -1)
        return -1;
    return 0;
}
//去空格
int getStringTrimSpace(char * str/*in*/,char * value/*out*/){
    if (str == NULL || value == NULL)
        return -1;
     int start = 0;
     int end = strlen(str) - 1;
     while (isspace(str[start]) && str[start] != '\0') start++;;
     while (isspace(str[end]) && str[end] != '\0') end--;
    strncpy(value,str+start,end-start+1);
    return 0;
}
  • const修饰符
const int A = 10;//常量
const char * str = NULL;//str所指向的内存不能被修改
char * const str = NULL;//str的指针地址不能被修改 
const char * const str;//只读
  • 二级指针内存模型
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

//分配内存
char ** getMemery(int num);
//显示
void printMyArray(char ** pstr,int num);
//排序
void sortArray(char ** str,int num);
//释放内存
void freeArray(char *** str,int num);


#define NUM 5

int main()
{
    char ** str = NULL;
    str = getMemery(NUM);
    printMyArray(str,NUM);
    sortArray(str,NUM);
    printMyArray(str,NUM);
    freeArray(&str,NUM);
    return 0;
}

char ** getMemery(int num/*in*/){
    int i = 0;
    char ** pstr = NULL;
    //分配一个指针数组
    pstr = (char **)malloc(sizeof(char *) * num);
    if (pstr == NULL)
        return NULL;
    for (i = 0;i < num;i++ )
     {
         //为指针数组里的每个指针所指向的内存空间分配内存
        pstr[i] = (char *)malloc(sizeof(char *) * 100);
        sprintf(pstr[i],"%d%d%d",i+1,i+1,i+1);
     }
     return pstr;
}

void printMyArray(char ** pstr/*in*/,int num/*in*/){
    int i  = 0;
    for (i = 0;i < num;i++){
        printf("%s\n",pstr[i]);
    }
}

void sortArray(char ** str/*in*/,int num/*in*/){

    int i = 0,j = 0;
    char * temp = NULL;

    for ( i = 0;i < num;i++){
        for ( j = i;j < num;j++){
            if (strcmp(str[i],str[j]) < 0){
                //交换的是指针的指向
                temp = str[i];
                str[i] = str[j];
                str[j] = temp;
            }
        }
    }
}

void freeArray(char *** str/*in*/,int num/*in*/){
    int i = 0;
    char ** temp = NULL;
    if (str == NULL)
        return ;
     //拿到二级指针
    temp = *str;
    for (i = 0;i < num;i++)
    {
        //释放一级指针
        free(temp[i]);
        temp[i] = NULL;
    }
    //释放二级指针
    free(temp);
    //注:temp = NULL 和 *str = NULL不同,temp = NULL并不能改变*str的指向
    *str = NULL;
}
  • 根据标识符切割字符串
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

int stringsplit(const char * str,char c,char *** pstr ,int * length);
int getstringleng(const char * str,char c,int * len,int * maxlen);
void printfArray(char ** str,int len);

int main()
{

    char * str = "aaa,bbb,cccc,ddddd,abcdefg,111,2222,333333";//测试数据
    int len = 0;
    char ** list = NULL;//创建数组
    stringsplit(str,',',&list,&len);//初始化数组
    printfArray(list,len);//显示
    //释放内存...
    //先释放一级指针,在释放二级指针
    return 0;
}

//显示
void printfArray(char ** str/*in*/,int len/*in*/){

    int i = 0;
    for (i = 0;i < len;i++){
        printf("[%s]\n",str[i]);
    }
}


//分配内存并切割字符串
int stringsplit(const char * str/*in*/,char c/*in*/,char *** arr/*out*/ ,int * length/*out*/){

    //为字符串末尾补充标识符
    char * newstr = (char  *)malloc(strlen(str) + 2);
    sprintf(newstr,"%s%c",str,c);

    int len=0;
    int maxlen = 0;

    if (!getstringleng(newstr,c,&len,&maxlen))
        return -1;

     printf("len = %d\n",len);
     printf("maxlen = %d\n",maxlen);

    char ** pstr = NULL;
    pstr = (char **)malloc(sizeof(char *) * len);

    char * temp = newstr;
    char * current = newstr;

    int i = 0;//pstr数组下标

    while (*newstr != '\0'){

        current = strchr(current,c);

        if (current != NULL){

            if (current - temp > 0){

                pstr[i] = (char *)malloc(sizeof(char) * maxlen + 1);
                strncpy(pstr[i],temp,current - temp);
                strncat(pstr[i],"\0",1);
                temp = current = current + 1;
                i++;
            }else{
                break;
            }

        }else{
            break;
        }
    }

    *arr = pstr;
    *length = len;

    free(newstr);
    newstr = NULL;

    return 0;
}

//拿到字符串的数量以及字符串的最大长度
int getstringleng(const char * str/*in*/,char c/*in*/,int * len/*out*/,int * maxlen/*out*/){

    if (str == NULL || len == NULL || maxlen == NULL)
        return -1;

    //临时指针
    char * pstr = str;
    char * temp = str;

    int count = 0;
    int index = 0;

    while (*str != '\0'){

        pstr = strchr(pstr,c);
        if (pstr != NULL){
            //防止标识符连在一起
            if (pstr - temp > 0){

                int tp = (int)(pstr - temp);
                if (tp > index)
                    index = tp;
                    count++;
                temp = pstr = pstr + 1;
            }else{
                break;
            }
        }else{
            break;
        }
    }

    *len = count;
    *maxlen = index;

    return 0;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值