栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c语言笔记(30)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c语言笔记(30)

文章目录
    • extern
    • 指针
      • 1. *(p++)与*(++p)
      • 2. 指针传参
      • 3. 数组与指针
      • 4. 指针与常量
    • 函数
    • 结构体
    • typedef
    • 声明与定义
    • attribute机制

extern

extern 除了可以让全局变量作用域拓展到其他文件,还能在一个文件内让全局变量拓展到整个文件。如

int main(int argc, char *argv[])
{
    //a的作用域原本在它声明的后方
    //没有extern就用不了a
    extern int a;
    a = 3;
    printf("a:%dn",a);
    return 0;
}

int a; //全局默认初始化为0

结果

指针 1. (p++)与(++p)

明确自加的顺序。P++是先用了后加,++p是先加了后用*(p++):先取p,用了之后,再偷偷加1,(++p):p先加1,再用

int main(int argc, char *argv[])
{
    int array[6] = {6,5,4,3,2,1};
    int *p1 = array, *p2 = array;

    printf("*(p++):%dn", *(p1++));//相当于*p1,即a[0]
    printf("*(++p):%dn", *(++p2));//相当于*(p2+1),即a[1]

    //p1用完之后偷偷自加,所以现在只想a[1]
    printf("after p1:%dn", *p1);
    printf("after p2:%dn", *p2);
    return 0;
}

结果

2. 指针传参

函数传参是采用“值传递”。当参数是指针的时候,可以改变指针变量指向的变量的内容(即可以用解引用改变值),但不能改变指针变量所指向的地址。如

void func(int *p)
{
    *p = 5;
    p= (int *)12345;
}

int main(int argc, char *argv[])
{
    int a=22, *p=&a;
    printf("before p:%pn", p);
    func(p);
    printf("a:%dnafter p:%pn", a,p);
    return 0;
}

结果

题外:

void func(int *p)
{
    p  (int *)12345;
    *p = 5;
}

这样是会出现段错误的。原因在于:对于可访问的内存地址才有资格去修改它的值,不可访问的内存是不能修改它的值。在这里它先修改了p所指向的地址,使p指向了一个未知的、不可访问的内存,然后再解引用自然是不可以的。

3. 数组与指针
char *p1 = "hello"; //√。让p1指向hello这个常量
char arr[10];       //×。这种错误就像 int a[10];
arr = "hello";      //              a={10,9};
return 0;
char *p1 = "hello"; 
char arr[] = "hello";     

p1[2] = 'a';  //×。
arr[2] = 'a'; //√。    
return 0;

当指针指向字符串常量的时候,不能通过指针去修改

4. 指针与常量
int arr[6] = {1,2,3,4,5};
int *p = &(arr[0]+2);

结果:编译报错

原因分析
a[0] = 0,程序的原意是想将p的解引用变为2,但这样子做是不对的。因为不能够给一个常量取址。编译器不再把arr[0]+2看作是一个变量,而是一个常数
int p = &(arr[0]+2); 等价于 intp = &2; 这两个写法都是不对的
int p = &(arr[0]+arr[2]); 等价于 int p = &2; 也是不对的。

int p =&(arr[0]+0); 不等价于 int p = &(arr[0]); 等价于 int * p = &(0);因为编译器已经把arr[0]+0 看做一个常数0

int * p = &(arr[0]); 这个是合法的,这个时候把arr[0]看成一个变量

函数

函数名代表函数的起始地址。如:

//功能:func1为带参函数,带的是函数指针。通过这个函数指针调用func2
void func1(void (*func2)(void));
void func2(void);

int main(int argc, char *argv[])
{
    func1(func2);//以func2作为函数指针
    return 0;
}

void func1(void (*func2)(void))
{
    printf("have used func1n");
    func2();
}

void func2(void)
{
    printf("have used func2n");
}

结果

结构体

同类的结构体变量可以相互赋值
结构体作为参数也是进行“值传递”,即还是会有形参实参之分,而且开销大,最好用指针的形式

typedef
typedef a b 把a这种数据类型取别名b
#define a b 把b用a来替换

typedef结构图的时候,结构体可以没有类型名。
typedef struct node
{
 int a;
 char b;
 float c;
} my_struct;

等价于

typedef struct 
{
 int a;
 char b;
 float c;
}my_struct;

typedef书写指南
1、按照定义变量形式写出来
2、变量名改成类型名
3、往最前加上typedef

例子:

① int [10] 被typedef为Num
1 :int a[10]
2 :int Num[10]
3 :typedef int Num[10]

② int (*)(void) 被typedef 为Pointer
1 :int (*p)(void)
2 :int (*Pointer)(void)
3 :typedef int (*Pointer)(void)
声明与定义

在C中,声明通常伴随着定义。

int a;  这里不仅有声明,还有定义。
extern int a; 这里只有声明
int a = 0; 声明、定义、初始化(定义之后同时赋值)。
int a; a=0; 声明、定义,然后赋值

声明不需要开辟新内存,定义则需要

attribute机制

attribute与它要限制的东西之间不宜加括号。如:
int num attribute((aligned(10241024))) ;
不能够写成:( int num attribute((aligned(10241024))) );

attribute((force))
作用是表示所定义的变量类型是可以做强制类型转换的,且让编译器不会发出警告。(但是亲测还是会)。
使用方法是:放在数据类型前面。如:

int a = 99;
int *p = __attribute__((force) int *)a;
printf("%pn",p);

结果

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/932339.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号