C笔记7:指针、结构体

目录

一.指针

1.指针变量

2.引用指针变量

3.指针变量的运算

4.指针数组和数组指针

a.指针数组

b.数组指针

c.指针与数组辨析

5.字符串指针 

6.指向指针的指针 

二.结构体

1.结构体变量

2.成员的获取和赋值

3.结构体数组

4.结构体指针

获取结构体成员


一.指针

1.指针变量

定义:数据在内存中的地址称为指针;存放地址的变量是指针变量,用来指向另一个变量。

格式为:数据类型  *指针变量名;

也可以在定义指针变量时对其初始化:数据类型 *指针变量名=值;  int *p=&a

注:该值前面必须要加取地址符&

2.引用指针变量

  • 赋值,如p=&a;
  • 引用值,如printf("%o" , p);  作用是以八进制数形式输出p的值;
  • 引用指向的变量,如p=&a;  printf("%d" , *p); 输出的是a的值。

3.指针变量的运算

指针变量保存的是地址,而地址本质上是一个整数,所以指针变量可以进行部分运算如++、--、+、- 、比较运算。

#include <stdio.h>
int main()
{
    int    a = 10,   *pa = &a, *paa = &a;
    double b = 99.9, *pb = &b;
    char   c = '@',  *pc = &c;    
    printf("&a=%#X, &b=%#X, &c=%#X\n", &a, &b, &c);
    printf("pa=%#X, pb=%#X, pc=%#X\n", pa, pb, pc);//最初的值
    
    pa++; pb++; pc++;
    printf("pa=%#X, pb=%#X, pc=%#X\n", pa, pb, pc);//加法运算
    
    pa -= 2; pb -= 2; pc -= 2;
    printf("pa=%#X, pb=%#X, pc=%#X\n", pa, pb, pc);//减法运算
    
    if(pa == paa)
    {
        printf("%d\n", *paa);
    }
    else{
        printf("%d\n", *pa);
    }                                //比较运算
    return 0;
}

结果为

可以看出,pa、pb、pc 每次加 1,它们的地址分别增加 4、8、1,正好是 int、double、char 类型的长度;减 2 时,地址分别减少 8、16、2,正好是 int、double、char 类型长度的 2 倍。

总结:

  • 指针的每一次递增,它其实会指向下一个元素的存储单元
  • 指针的每一次递减,它都会指向前一个元素的存储单元。
  • 指针在递增和递减时跳跃的字节数取决于指针所指向变量数据类型长度,比如 int 就是 4 个字节。

4.指针数组和数组指针

a.指针数组

数组中的所有元素都是连续排列的,整个数组占用的是一块内存,定义数组时所给出的数组名可以认为是一个指针,它指向数组的第0个元素。我们把第0个元素的地址成为数组的首地址

例,以指针的方式遍历数组元素:

#include <stdio.h>
int main(){
    int arr[] = { 99, 15, 100, 888, 250 };
    int len = sizeof(arr) / sizeof(int);  //求数组长度
    int i;
    for(i=0; i<len; i++){
        printf("%d", *(arr+i) );  //*(arr+i)等价于arr[i]
//arr表示数组首地址,arr+i指向数组的第i个元素,*(arr+i)表示取第i个元素的数据

    }
    printf("\n");
    return 0;
}

结果为

99 15 100 888 250

b.数组指针

 数组指针,即指向数组的指针。

例:

int arr[] = { 99, 15, 100, 888, 252 };
int *p = arr;

注:arr本身被转换成了一个指针,可以直接赋值给指针变量p,int *p = arr;  也可以写作 int *p=&arr[0]; 

区分:

*p++:等价于*(p++),表示先取得第n个元素的值,再将p指向下一个元素;

*++p:等价于*(++p),会先进行++p运算,使得p的值增加,指向下一个元素,整体上相当于              *(p+1),会获得第n+1个数组元素的值;

(*p) ++:先取得第n个元素的值,再对该元素的值加1。

c.指针与数组辨析

数组名称和指针变量的唯一区别是,不能改变数组名称指向的地址,即数组名称可视为一个指向数组首元素地址的指针常量

也就是说数组名指针是定死在数组首元素地址的,其指向不能被改变。比如数组名不允许自加A++,因为这会它是一个不可改变的指针常量,而一般指针允许自加p++;还有常量不能被赋值,即若有数组名 A,指针p,则A = p是非法的。

5.字符串指针 

除了字符数组,C语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串,例如:

char *str = "c.program";

或者:

char *str;
str = "c.program";

输出字符串:

#include <stdio.h>
#include <string.h>
int main(){
    char *str = "c.program";
    int len = strlen(str), i;
   
    printf("%s\n", str); //直接输出字符串
    

    for(i=0; i<len; i++){
        printf("%c", *(str+i));
    }
    printf("\n");        //使用*(str+i),该形式的字符串称为字符串常量


    for(i=0; i<len; i++){
        printf("%c", str[i]);
    }
    printf("\n");        //使用str[i]
    return 0;
}

结果均为  c.program

注: 字符串常量只能读取,不能写入。

6.指向指针的指针 

指向指针的指针变量必须声明,即在变量名前放置两个星号。例如,下面声明了一个指向 int 类型指针的指针:int **var; 第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。


二.结构体

定义:用来存放不同类型数据的数据类型

struct 结构体名

{

        结构体所包含的变量或数组

};

其中,所包含的变量或数组都称为结构体的成员。其定义方式与变量和数组的方式相同,但不能初始化。

1.结构体变量

即,用结构体来定义变量。

例:

struct stu stu1, stu2; //定义了两个变量,都是stu类型,关键字struct不能少

也可以在定义结构体的同时定义结构体变量,将变量放在结构体定义的最后即可。

例:

struct stu{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    char group;  //小组
    float score;  //成绩
} stu1, stu2;

2.成员的获取和赋值

获取结构体成员的一般格式为: 结构体变量名. 成员名; 

也可以在后面加=赋值,如stu1.name="Tom";   (对成员进行逐一赋值)

 赋值:除逐一赋值外,还可以在定义结构体时整体赋值,如:

struct{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    char group;  //所在小组
    float score;  //成绩
} stu1, stu2 = { "Tom", 01, 19, 'A', 135.6 };

3.结构体数组

即数组中的每个元素都是一个结构体。

定义结构体数组,例:

struct stu{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    char group;  //所在小组 
    float score;  //成绩
}class[5];

在定义的同时也可以初始化:

struct {
        char *name;
        int no;
        char *gender;
        int sage;
    }class[] = {
        {"Li Ping",5,"男",18},
        {"Zhang Ping",4,"男",19},
        {"He Fang",1,"女",18},
        {"Chen Ling",2,"女",19},
        {"Li He",3,"男",20}
    };      //对数组中全部元素赋值时,可以不给出数组长度

4.结构体指针

当一个指针变量指向结构体时,称为结构体指针。

定义形式:

struct 结构体名 *变量名

例:

struct stu{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    char group;  //所在小组
    float score;  //成绩
} stu1 = { "Tom", 12, 18, 'A', 136.5 };//结构体

struct stu *pstu = &stu1;//结构体指针

 也可以定义结构体的同时定义结构体指针:

struct stu{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    char group;  //所在小组
    float score;  //成绩
} stu1 = { "Tom", 12, 18, 'A', 136.5 }, *pstu = &stu1;

获取结构体成员

通过结构体指针可以获取结构体成员,形式为:

(*pointer).memberName

pointer->memberName

 例:

//读取结构体成员的值
printf("%s的学号是%d,年龄是%d,在%c组,今年的成绩是%.1f!\n", (*pstu).name, (*pstu).num, (*pstu).age, (*pstu).group, (*pstu).score);

printf("%s的学号是%d,年龄是%d,在%c组,今年的成绩是%.1f!\n", pstu->name, pstu->num, pstu->age, pstu->group, pstu->score);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在C语言中,我们经常会使用结构体来组织一些数据,而结构体中也可能会包含指针类型的成员。当我们对整个结构体进行初始化时,需要考虑如何初始化指针类型的成员。 这时,我们可以使用C标准库中的memset函数来进行初始化。memset函数可以将一块内存区域的值全部设置为某个给定的值。其函数原型如下: ```c void *memset(void *s, int c, size_t n); ``` 其中,s表示要填充的内存区域的起始地址,c表示要填充的值,n表示要填充的字节数。 对于结构体中的指针类型成员,我们可以将其设置为NULL,表示该指针指向空地址。例如,下面是一个结构体及其初始化示例: ```c #include <stdio.h> #include <string.h> struct Student { char name[50]; int age; float score; struct Student *next; }; int main() { struct Student stu; memset(&stu, 0, sizeof(stu)); printf("name: %s\n", stu.name); printf("age: %d\n", stu.age); printf("score: %f\n", stu.score); printf("next: %p\n", stu.next); return 0; } ``` 在上面的示例中,我们定义了一个Student结构体,其中包含了一个指向下一个结构体指针类型成员next。在main函数中,我们使用memset函数将整个结构体初始化为0,包括指针类型成员next。输出结果如下: ``` name: age: 0 score: 0.000000 next: (nil) ``` 可以看到,对于指针类型成员next,其被初始化为了NULL,即空地址。这样,在程序中使用该结构体时,我们就可以通过判断指针是否为NULL来进行相关操作了。 ### 回答2: 在C语言中,使用memset函数可以将一块内存区域的内容全部设置为指定的值。其中,结构体是一种自定义的数据类型,可以将不同类型的变量组合在一起,形成一个新的数据类型。 在使用memset函数对结构体进行初始化时,需要注意结构体指针的处理。由于memset函数只能对连续的内存区域进行初始化,而指针成员变量所指向的内存区域往往不连续,因此不能直接对指针进行初始化。 如果要对结构体内的指针进行初始化,可以采用以下方法之一: 1. 使用静态初始化:通过给结构体指针成员变量赋初值,将其指向一个已经分配好内存的对象或数组。例如,可以使用malloc函数动态分配内存,并将指针成员变量指向该内存区域。 ``` struct Example { int* ptr; }; // 静态初始化 int main() { struct Example ex; int value = 1; ex.ptr = &value; return 0; } ``` 2. 在结构体定义之后,使用malloc函数为指针成员变量分配内存。这样可以确保在使用memset函数初始化结构体之前,指针成员变量已经指向了有效的内存地址。 ``` struct Example { int* ptr; }; // 动态初始化 int main() { struct Example ex; ex.ptr = malloc(sizeof(int)); memset(&ex, 0, sizeof(ex)); return 0; } ``` 需要注意的是,在使用完内存后,要记得使用free函数释放动态分配的内存,避免内存泄漏。 总之,在使用memset函数初始化结构体时,需要考虑结构体指针的处理,可以使用静态初始化或者在结构体定义后动态分配内存。 ### 回答3: memset是C语言中的一个库函数,用于按字节对特定内存块进行初始化或设置。它的原型为void *memset(void *ptr, int value, size_t num)。 对于结构体内的指针,memset函数通常不能直接使用。这是因为memset仅用于按字节进行内存设置,对于指针类型的变量,只会设置指针本身的值,而不会处理指针所指向的内存块。 如果我们想要将结构体内的指针进行初始化,可以使用其他方法。一种常用的方法是使用malloc函数动态分配内存,并将指针指向这块内存。例如: ```c #include <stdlib.h> typedef struct{ int* ptr; } MyStruct; void initStruct(MyStruct* s){ s->ptr = malloc(sizeof(int)); *s->ptr = 0; } ``` 在上述代码中,我们定义了一个结构体MyStruct,其中包含一个指向int类型的指针ptr。通过initStruct函数,我们可以为MyStruct类型的实例进行初始化,即将ptr指针动态地分配为一块int类型的内存,并设置其初始值为0。 需要注意的是,在使用完分配的内存后,我们需要使用free函数来释放内存,防止内存泄漏。 在C语言中,结构体、链表和枚举是非常常用的数据结构和语法特性。结构体用于组合不同类型的数据,形成一个自定义的数据类型;链表用于存储动态数据集合,其特点是可以灵活地添加和删除元素;枚举用于定义一组有限的命名常量,使代码更加易读和易维护。在实际编程中,合理使用这些特性可以提高代码的可读性和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值