关于C语言的一些总结(菜鸟版本)

typedef unsigned int  uint16;

define  num 8

数组int a[10]   typedef struct ab {uint16 a; uint16 b; uint16 c;}abb;   abb stu[10];    void fun() ;    其中数组的名字a 和stu   函数名fun代表首地址,

但是,如果是单独的结构体,abb stu;  stu并不代表首地址,首地址要用到&符号

 

a+3 代表第三元素的地址  a[3]代表第三个元素  同理   stu[1]不是代表地址,而是第二个结构体本身,可以这样复制stu[1].a=2;

stu+1才代表第二个结构体的地址

与&stu[1]是一个意思

 

printf

字符对应数据类型含义
d / iint接受整数值并将它表示为有符号的十进制整数,i是老式写法
ounsigned int无符号8进制整数
u
unsigned int无符号10进制整数
x / X
unsigned int无符号16进制整数,x对应的是abcdef,X对应的是ABCDEF
f
float或double单精度浮点数双精度浮点数
e / E
double科学计数法表示的数,此处"e"的大小写代表在输出时用的“e”的大小写
g / G
double使用以上两种中最短的形式,大小写的使用同%e和%E
c
char字符型。可以把输入的数字按照ASCII码相应转换为对应的字符
s / S
char * / wchar_t *字符串。输出字符串中的字符直至字符串中的空字符(字符串以'\0‘结尾,这个'\0'即空字符)
p
void *以16进制形式输出指针
nint *到此字符之前为止,一共输出的字符个数,不输出文本
%
无输入不进行转换,输出字符‘%’(百分号)本身
注:%g、%G在小数点位数四位或指数大于等于精度时用%e、%E,否则用%f。

 

 

int main(int argc, char ** argv)       int main(int argc,char * argv[])

 

int a=10 b=20 c=30

printf("%d%d%d",a+b+c,b=b*2,c=c*2) ;   结果 110  40  60  因为函数的参数默认是从右到左处理的。

 

 

char *p  p是指针变量,其值是可以修改的,但是不能通过P修改指向的字符串

char p【】   p是数组变量,其值不可以修改,但是可以修改p指向的字符串

 

 

连接符 #define XXX(a,b)  a##b    //##  是连接符

printf(“%d\n”,XXX(fun,2)(100));

 

等价于 fun2(100);

 

 

 

 

 

 

地址空间:为了比较直观的知道地址空间的大小,可记以下规律。4K     --> 0x00001000,

                                                                                            64K   --> 0x00010000,

                                                                                            1M    --> 0x00100000, 

                                                                                              16M --> 0x01000000, 

                                                                                            256M-->   0x10000000,           
3个0 是4K                         4个0 是64K                      5个0 是1M                     6个0 是16M                 7个0 是256M

为什么3个0表示的空间大小是4K小呢? 地址从0x00000000起始,到0x00001000其间则有16*16*16个地址,每一个地址表示1bit空间大小。 那其空间大小是:(16*16*16)/1024= 4 k

每个地址,如0x10000000单个地址,它是16进制,所以每一个数值需要4个bit来表示(2的4次方=16), 所以其占用空间32bit。

为什么bit成为了最小数据单元?(以下为个人的理解) 电子电路它只有0,1两种信号(再傻瓜式的说明就是只有通电或断电),所以我们定义了能标志0或1的单元为bit。然后我们开始采用顺序堆积很多这样单元,就能为我们记录很多标识(称作数据或信息)。
但是是谁在控制这个16进制的地址呢,是CPU吗?或说是这么多16进制的数值(编号)它又是保存在那呢?每个bit空间,是不可能存放一个32位的16进制的,就算可以也没有意义。那CPU它又是根据什么来进行寻址呢?它是如何做到可以直接跳转读取到指定的地址?

2.

名称标识符大小表示范围
短整型shortint1字节-128~127
整型integer2字节-32768~32767(-2^15~2^15-1)
长整型longint4字节(-2^31~2^31-1)
64位长整形int648字节-2^63~2^63-1
字节型byte1字节0~255
字型word2字节0~65536
双字型dword4字节
四字型qword8字节0~2^64-1
允许的计算符是+(加) -(减) *(乘) div(整除) mod(求余)and (与)or (或)xor(异或)
 

1.typdef void (*funcptr)(void);的解释说明( 函数指针)    原型初见于stm32的IAP bootloader编程“跳转地址函数”
定义一个函数指针类型。
比如你有三个函数:
void hello(void) { printf("你好!"); }
void bye(void) { printf("再见!"); }
void ok(void) { printf("好的!"); }

typdef void (*funcptr)(void);
这样就构造了一个通用的函数
你用的时候可以这样:
void speak(int id)
{
   funcptr words[3] = {&hello, &bye, &ok};
   funcptr fun = words[id];
   (*fun)();
}

这样的话,如果speak(0)就会显示“你好!”
speak(1)就会显示“再见!”
speak(2)就会显示“好的!”

用于处理参数和返回值的形式都一样,但是功能不确定的一组函数,可以使用函数指针。
比如算术运算符,加、减、乘、除,都可以用typedef int (*calc)(int,int)代表,等、

 

2.(指针和形参传递)

1.       零值比较

一般意义上的零值有布尔型,整型,指针,浮点型。

(1)             布尔型:C语言里面没有布尔类型,但是C99标准提供了一个库来表示,头文件为<stdbool.h>,其表示为bool mybool = true;注意都是小写,其实在C语言windows里面也定义了一个BOOL来区别于C++bool

1)         #include <stdbool.h>

2)          

3)         int main(void)

4)         {

5)                  bool mybool = true;

6)                  if(mybool)

7)                            printf("mybool is true\n");

8)                  else

9)                            printf("mybool is false\n");

10)          printf("c bool size is %d\n", sizeof(mybool));

11)               return 0;

12)      }

结果为:

mybool is true

c bool size is 4

 

注意和C++的布尔型的区别,C语言里面的布尔型是用整数来代替的,零是假,任何非零的值为真,C++的布尔型是一个一个字节的变量。

1)         //#include <stdbool.h>

2)         #include <iostream>

3)         using namespace std;

4)         int main(void)

5)         {

6)         bool mybool = true;

7)         if(mybool)

8)         cout<<"mybool is true"<<endl;

9)         else

10)      cout<<"mybool is false"<<endl;

11)      cout<<"c++ bool size is "<<sizeof(mybool)<<endl;

12)      return 0;

13)      }

结果为:

mybool is true

c++ bool size is 1

(2)             整型:同类bool型用法一样 int test = 0;

if(test){

}

else{

}

(3)             指针:指针的零值为空指针NULL int *ptest = NULL;

 

if(test == NULL){

}

else{

}

(4)             浮点型:浮点型的数据与零值比较不是直接测试与零是否相等,而是测试是否在0值左右的一个范围内。

if(fabs(flag2) < 1e-5)

        printf("flag2 is 0\n");

    else

        printf("flsg2 is not 0\n");

 

2.       函数形参传递

 

1Strcpy函数的实现:

char *mystrcpy(char *des, const char *sur)

{

char *p = des;

assert((des !=NULL ) && (sur != NULL));

while((*des++=*sur++) != '\0');

return p;

}

2)示例1

1)       void getmemory1(char *p)

2)       {

3)       p = (char *)malloc(100);

4)       }

5)       void test1(void)

6)       {

7)       char *str = NULL;

8)       getmemory1(str);

9)       strcpy(str, "hello world1 \n");

10)    printf(str);

11)      }

由于传入函数getmemory1的参数为指针,编译器为其准备一个副本_p传入,存在在系统栈里面,我们在getmemory1函数里面,为其动态分配空间存在于堆上,但是里面使用的是p的副本,分配空间的头指针指向的是_p,而不是p,所有该函数结束时p的值仍然没有改变,这里函数结束后不会把分配的空间释放掉,因为其分配的空间在堆上,如果程序员不释放的话其空间要在程序结束后由操作系统收回。测试函数使用未改变的的指针,其值为NULL,所有会出错。

3)示例2

1)       char* getmemory2(void)

2)       {

3)      char p[] = "hello world2 \n";//在栈上

4)       return p;

5)       }

6)       void test2(void)

7)       {

8)       char *str = NULL;

9)       str = getmemory2();

10)    printf(str);

11)      }

由于函数getmemory2在内部使用了char p[] = "hello world2 \n"; 所有我们这里说一下他和

 

char  *p1 = "hello world2 \n";的区别,首先char p[] = "hello world2 \n"都是存放在栈上的,函数执行完会自动释放,而char  *p1 = "hello world2 \n";却不一样,char *p1存放在栈上这与前面一样,但是"hello world2 \n"却是存放在常量区的,程序结束后由系统释放 ,而且char p[]是一个数组名,为常量,而char  *p1不是,在getmemory2函数中,char p[] = "hello world2 \n"都是存放在栈上的,函数作用范围结束后会自动释放,所以,即使返回了p指针,我们打印出来的字符串也是乱码但是如果将函数内部char p[] = "hello world2 \n"改变为char  *p1 = "hello world2 \n",则不会出错,程序代码如下:

 

1)         char* getmemory2(void)

2)         {

3)         char *p1= "hello world2 \n";

4)         return p1;

5)         }

6)         void test2(void)

7)         {

8)         char *str = NULL;

9)         str = getmemory2();

10)      printf(str);

11)      }

 

从这里我们可以认为,char p[] = "hello world2 \n"是一个字符型数组,p为数组名不可以改变,而char  *p1 = "hello world2 \n"是指针指向的字符串常量,p1为可变指针,而字符串常量存在常量区。

 

(4)外传:字符串常量,我们可以知道"hello world2 \n"是一个字符串常量,并将第一个值的位置给一个指针p1,我们来看一下下面的表达式:

 

"hello world2 \n"+1

 

其实我咋一看,感觉这表达式没什么意义,在看了C和指针才知道,其实这个也是很有意思的,

 

"hello world2 \n"+1指向的是字符串常量的第二个字符,这样我们干脆就把它当成一个指针来看,这样下面的表达式也就有了意义

 

*"hello world2 \n"

 

这个表达式很明显的意思就是取字符串常量的第一个字符,依次我们可以进行的运算就可以知道如

 

"hello world2 \n"[3]; //等效于*("hello world2 \n"+3)

 

注意:由于字符串常量位于常量区,他的生命周期是恒定不变的,而且由于是常量,它不允许改变它的值,是只读的。

 

5)示例3

 

1)         void getmemory3(char **p, int num)

2)         {

3)         *p = (char *)malloc(num);

4)         }

 

5)         void test3(void)

6)         {

7)         char *str = NULL;

8)         int num = 100;

9)         getmemory3(&str,num);

10)      printf(str);

11)      }

 

这次这个示例可能有点难懂了,传入函数getmemory3可以说是指针的指针,假设这里编译器为其准备的副本为__p,那么*__p即是指向char类型的指针,那么我们可以像平常那样对其动态分配空间,你可能会有疑问,为什么这里可以为他动态分配呢,虽然编译值指定__p = p;

 

但是他们指向的地址都是同一个,*__p =  *p,分配空间后的头指针付给*__P 相当于赋给了*p,但是最好不要用这个方法分配空间。

注意:释放分配的空间后将指针设置为NULL,避免形成野指针。

6)示例4

 

1)         char* getmemory3(void)

2)         {

3)         char *p = (char *)malloc(100);

4)         printf("len is %d \n",strlen(mystrcpy(p, "hello mywold3")));

5)         return p;

6)         }

 

 

7)         void test3(void)

8)         {

9)        char *str = NULL;

10)      str = getmemory3();

11)      printf(str);

12)      }

 

getmemory3函数里面,char *p = (char *)malloc(100);分配空间,虽然指针p存在于系统栈在函数结束后将消亡,但是分配的空间存在于堆不会,返回分配的首指针,使该动态分配的区域有指针指向,置于可用状态。

3.       指针

我们这里直接通过下面一段代码来讲解:

 

char ch[7]="13579";

    char cr = 'm';

    char *cp = &cr;

    printf(" &cr is %0x\n", &cr);//取cr变量的地址,也就是m存储的位置

    printf(" cp is %0x\n", cp);/变量赋值的时候就是为m存储的位置

    printf(" &cp is %0x\n", &cp);//取cp的地址

    printf(" *cp is %c\n", *cp);//从存储m的位置,取出m

    cp = ch;

    printf(" *cp+1 is %c\n", *cp+1);//从存储m的位置,取出m并将m的值加‘*’优先级高

    printf(" *(cp+1) is %c\n", *(cp+1));//地址cp加单位字节,然后取出+1地址的内容

    printf(" cp is %0x\n", cp)

    printf(" ++cp is %0x\n", ++cp);//地址cp先加单位字节再使用

    printf(" cp is %0x\n", cp);

    printf(" cp++ is %0x\n", cp++);//地址cp先使用再加单位字节

    printf(" *cp is %c\n", *cp);

    printf(" *++cp is %c\n", *++cp);//*,++优先级相同,自右向左,先指针加1再取内容

    printf(" *cp is %c\n", *cp);

    printf(" *cp++ is %c\n", *cp++);//*,++优先级相同,自右向左,先取内容再指针加1

//其实这里挺奇怪的 两者优先级相同,且是从右向左,那就应该是先++,但是我们这里可以这//样认为两者操作符没有挨着,所有遵循从左到右,先取值,再指针+1

    printf(" *cp is %c\n", *cp);

    printf(" ++*cp is %c\n", ++*cp);// *,++优先级相同,自右向左,先取内容再内容加1

 

转载于:https://www.cnblogs.com/darren-715/p/3456951.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值