C语言指针知识记录

C语言指针知识记录

  • 前言
    在学习过程中老是遇到很多坑,或者单纯是自己没掌握好的东西。不记录下来过一段时间又忘了。因此写下来作为记录,希望能帮到后来的朋友爬坑,同时也方便自己以后查阅。如有不正确的地方欢迎指出。

  • 地址
    程序的数据是存储在电脑中的虚拟存储器中的。这个虚拟存储器里面有许多单元,每个单元都有自己的标号,也就是这个单元的地址。指针的本质就是某个单元的地址。
    比如,int n = 5 ; 声明了一个叫n的变量,并把它的值赋为5。在计算机内部这个值实际是虚拟存储器的某个单元中的,这个单元的地址可以通过取地址符号,&n获得。
    其实可以把虚拟内存看成一个很大的数组,指针就是数组的下标。&n就是取存了n的单元的下标。
#include 
int main(void)
{
    char ch = 'a';
    int  n = 5;
    printf("ch 的地址:%p\n",&ch);   //ch 的地址:0061FECF
    printf("n  的地址:%p\n",&n);  //n  的地址:0061FEC8
    return 0;
}
  • 指针
    指针的本质是某个单元的地址,因此赋值时候,就应该把一个地址赋给它,比如int *p = &n;表示的是申请了一个int类型的指针,这个指针的内容为n的地址。因此,这个指针也就指向了n的。
    p是一个指针,*p为指针所指向的内容。
#include 
int main(void)
{
    int  n = 5;
    int *p = &n;
    printf("p   的值:%p\n",p);    // p的值:0061FEC8
    printf("*p  的值:%d\n",*p);   // *p的值:5
    return 0;
}

关于指针的最基础的知识就是这些了,更详细更深入的知识可以参考博客: C语言指针详解


下面写一写我在学习中遇到的坑。

1. 字符串常量

先来看一段会报错的代码。原因是 “helloworld” 被存在一个只读的区域中,所以其实是常量,不能被修改。我这里是程序异常终止Process finished with exit code -1073741819 (0xC0000005)。

#include 
int main(void)
{
    int i ;
    char *s1 = "helloworld";
    s1[0] ='H';
    printf("%c",s1[0]);
    return 0;
}

解释:
在C语言中 “helloworld” 叫做字符串字面量,也叫字符串常量。“helloworld” 会被编译器编程一个字符数组放在某处,这个数组的长度是 “helloworld” 的长度加1。(字符串末尾有\0)
char *s = “helloworld"含义为:s是一个指针,指向一个字符串常量,这个字符串常量是在编译的时候赋值的,被储存在一个叫"代码段”,这个地方是只读的。
因此char *s = “helloworld” 实际上是 const char *s = “helloworld”
接下来再看一段代码:

#include 
int main(void)
{
    int i ;
    char *s1 = "helloWorld";
    char *s2 = "helloWorld";
    printf("&i = %p\n",&i);
    printf("s1 = %p\n",s1);
    printf("s2 = %p\n",s2);
    return 0;
}

通过以上代码可知,s1,s2因为指向同一个区域,因此相同。并且,s1,s2都比较小,明显和i的地址不在同一块区域。
关于不同变量存储位置详细可以参考博客C/C++程序内存的各种变量存储区域和各个区域详解


2. 用指针代替二位数组

前段时间写了个代码实现矩阵的基本运算。矩阵的数据结构如下。

typedef struct {
double  **mat;
int      row;
int      col;
}Matrix;

用 **mat 代替 mat[MAXN][MAXN] 就能利用malloc开出合适的空间,避免空间浪费。
但由于学艺不精,把自己搞迷糊了,调试了很久才弄对。下面是矩阵初始化函数的代码。

void InitialMatrix(Matrix *T, int row, int col) {
    T->row = row;
    T->col = col;
    T->mat = (double**)malloc(sizeof(double*)*row);
    for (int i=0;imat[i] = (double*) malloc(col*sizeof(double ));
}

存储结构即为先申请row个指针,让他们分别指向col个double的空间。


3. 指针代替结构体数组

做大作业学生成绩管理系统,自己做肯定会用链表来存学生信息,但根据题目要求来看,得做成结构体数组的形式,当然还是需要用到指针,不能暴力的就来一个student stu[MAXN] 了。虽说现在的计算机也不差那点空间了,但是该学的知识还是要学好,奈何本人实在太菜,又被卡了很久。
下面是学生信息数据结构。

typedef struct
{
    int id;
    char name[50];
    float chinese;cloat english; float math;float sum;
}student;

下面是题目的主程序。stu是一个指针,学生信息是存在一个指针里的,但给出的学生信息数据结构并不是链表。 ReadStuInfoFromFile ( ) 传入的又是stu这个指针的地址。没办法了,只能在ReadStuInfoFromFile ( ) 做一个结构体数组,然后将stu修改为这个结构体数组的地址。

int main() {
    int n, rank, id,i,m;
    student *stu =NULL;
    n = ReadStuInfoFromFile(filepath,&stu);
    PrintStudents(stu, n);

下面是ReadStuInfoFromFile () 的实现。

int ReadStuInfoFromFile(char *filepath,student ** pstu) {
    FILE *fp = NULL;
    fp = fopen(filepath,"r");
    if (fp==NULL) return 0;
    int n;
    fscanf(fp,"%d",&n);
    /* 只关注下面数据结构实现的部分*/
    student  *stu;
    stu = (student*) malloc(n*sizeof(student));
    for (int i = 0; i < n ; ++i) {
        fscanf(fp,"%d %s %f %f %f",&stu[i].id,stu[i].name,&stu[i].chinese,&stu[i].math,&stu[i].english);
        stu[i].sum = stu[i].chinese+stu[i].english+stu[i].math;
    }
    *pstu = stu;
    fclose(fp);
    return n;
}
  1. 在ReadStuInfoFromFile ( ) 里,stu是一个指针,即stu得到应该是一个地址。
  2. malloc申请了一个大小为 n* sizeof(student) 的空间,是一片可分成 n 份的连续的空间,其实也就是一个产生了一个student类型的数组。这个数组的地址即为这这片空间的首地址。因此stu最后得到的其实就是这片空间的的首地址。
  3. 前面说过要将main() 里的stu改为结构体数组的地址。
    pstu 是 main() 函数里的stu的地址,因此修改main() 里的stu ,需要通过 *pstu来修改。
    因此 *p = stu;

暂时就先写到这里了,以后遇到关于指针的问题再来补充。

你可能感兴趣的:(经验分享)