首页 > 其他分享 >C语言——指针

C语言——指针

时间:2023-06-02 11:04:30浏览次数:45  
标签:int C语言 char ++ printf include 指针


指针的优点:

  1. 使程序更简洁、紧凑、高效
  2. 有效的表达更复杂的数据结构
  3. 动态分配内存
  4. 得到多于一个数的函数返回值

1. 指针的基本用法

1.1 指针的概念

  • 内存地址:内存中每个字节单位都有一个编号(一般用十六进制表示)
  • 指针:指针就是内存地址
  • 指针变量:用于存放地址的变量就叫做指针变量

C语言——指针_c语言

指针变量画图展示:

C语言——指针_c++_02

1.2 格式

存储类型 数据类型 *指针变量名;

int *p; //定义了一个指针变量p,指向的数据是int类型的。

int a = 5;
int *p = &a;
char c='v';
char *q=&c;
printf("%p %p\n", p, &a);
printf("%p %p\n",q,&c);
printf("%d %d\n",a,*p);
printf("%c %c\n",c,*q);

访问指针所指向空间的内容用取内容运算符*

那么p变量存放的就是a的地址,q变量存放的是c的地址。

符号*可以访问地址里面的内容。

指针与所指变量之间的关系如下图:

int i=3;

int *i_potinte=&i;

C语言——指针_c++_03

2.3 指针操作符

  • &:取地址符:取变量的地址
  • *:取内容符:取地址里面存放的内容

*&a=a;//*和&是互逆运算

&*a//错误(因为运算符优先级)

2.4 指针变量初始化和赋值

指针变量使用前不仅要定义,还要初始化。未初始化的指针变量不能随便使用,不然可能会产生野指针。

(1)将普通变量的地址赋值给指针变量

#include 
int main(int argc, char const *argv[])
{
    int a=10;
    int *p = &a;//定义的同时赋值
    int *q=NULL;//可以初始化为空指针
    int *p2;
    p2=p;//先定义后赋值

    printf("%d %d %d\n",a,*p,*p2);//打印a的值
    printf("%p %p %p\n",&a,p,p2); //打印a的地址
    *p=20;                        //同过指向a的指针改变a的值
    printf("%d %d %d\n",a,*p,*p2);//打印a的值
    printf("%p %p %p\n",&a,p,p2); //打印a的地址
    return 0;
}

(2)将数组的首地址赋值给指针变量

char s[10]="hello";
char *p = s;
int arr[5]={1,2,3,4,5};
int *q=arr;
printf("%c\n",*p);//h
printf("%d\n",*q);//1

(3)将指针变量里面保存的地址赋值给另一个指针变量

int a=10;
    int *p=&a;
    int *q=p;
    printf("%d %d %d\n",a,*p,*q);
    *q=20;//通过指针改变变量a的值
    printf("%d %d %d\n",a,*p,*q);

p和q都指向了变量a

2. 指针运算

2.1 算术运算- +

对指针加减操作其实就是让指针向前向后移动

char str[32]="hello";
    char *p=str;
    printf("%c\n",*p);
    p++;
    printf("%c\n",*p);
    p--;
    printf("%c\n",*p);

int *p;p++;//移动4字节

double *q;q++;//移动8字节

p+n:访问高地址方向的第n个数据的地址,指针的指向不发生变化。

p-n:访问低地址方向的第n个数据的地址,指针的指向不发生变化。

偏移了多少字节=n*sizeof(数据类型)

2.2 关系运算 > >= < <= == !=

指针之间的关系运算比较的是它指向地址的高低

指向高地址的指针是大于指向低地址的指针

char s[10]="hello";
    char *p1=s;
    char *p2=&s[2];
    if(p2>p1)
        printf("p2>p1");
    else 
        printf("p2);

练习:以下程序打印出来什么

char s[32]="hello";
char *p=s;
p++;c
char y=(*--p)++;
printf("%c",y);//h

练习:以下程序打印什么结果

int x[] = {10, 20, 30};
int *px = x;
printf("%d,", ++*px);//11
printf("%d\n", *px); //11
px = x;
printf("%d,", (*px)++);//11
printf("%d\n", *px);//12
px = x+1;
printf("%d,", *px++);//20
printf("%d\n", *px);//30
px = x+1;
printf("%d,", *++px);//30
printf("%d\n", *px);//30

练习:下面程序段的运行结果是

char a[ ]=”language” , *p ;
p=a ;
while (*p!=’u’) { printf(“%c”,*p-32); p++ ; }
A)LANGUAGE B)language C)LANG D)langUAGE
C

3. 指针的大小和段错误

3.1 指针的大小

计算指针大小用:sizeof(指针变量名)

int a=5;
    short b=6;
    char c='a';
    int *p1=&a;
    short *p2=&b;
    char *p3=&c;
    printf("%d %d %d\n",sizeof(p1),sizeof(p2),sizeof(p3));//4 4 4 4

总结:

  1. 32位操作系统指针大小是4字节。64位操作系统,指针大小是8字节。
  2. 内存地址是固定的,但是变量的地址不是固定的。
  3. 指针类型根据指针指向的空间的数据类型来匹配

练习:
利用指针判断输入的字符串是否为回文

#include 
#include 
int main(int argc, char const *argv[])
{
   char a[32]={};
   char *p1,*p2;
   int flag=1;
   gets(a);
   p1=a;
   p2=a+strlen(a)-1;
   while(p2>p1)
   {
       if(*p1!=*p2)
            flag=0;
       p1++;
       p2--;
   }
    if(flag==0)
        printf("no!\n");
    else 
        printf("yes!\n");
    return 0;
}

练习:编写一个程序实现功能:将字符串“Computer Science”赋值给一个字符数组,然后从第一个字母开始间隔的输出该字符串,用指针完成。结果:Cmue cec

#include 
#include 
int main(int argc, char const *argv[])
{
    char string[32] = "Computer Science";
    char *p = string;
    while (*p != '\0')
    {
        printf("%c", *p);
        p += 2;
    }
    printf("\n");
    return 0;
}

3.2 使用指针时报段错误

段错误: Segmentation fault (core dumped)

(1)野指针,没有规定指向的指针会在内存中乱指。

野指针产生的原因,主要有两种:

【1】指针变量没有初始化

【2】指针被free之后,没有置NULL,会让人认为时合法指针。

这两种情况都是没有给指针规定指向。

例如:int *p;

scanf(“%d”, p);

printf(“%d\n”,*p);

修改:

int a=10;
    int *p=&a;
    scanf("%d",p);
    printf("%d\n",*p);

(2)内存泄露,对非法空间进行赋值。

练习1.将字符串转换成整型数字输出。用指针实现

#include 
#include 
int main(int argc, char const *argv[])
{
    char a[32]="123";
    char *p=a;
    int num=0;
    while(*p != '\0')
    {
        num = num*10+(*p-48);
        p++;
    }
    printf("num=%d\n",num);
    return 0;
}

4. 指针修饰

4.1 const 常量化

(1)修饰普通变

const int a=10;

int const b=10;

此时a和b只读,不可以修改。但是可以通过指针修改。

const int a=10;
    int const b=20;
    int *p=&a,*q=&b;
    printf("%d %d\n",a,b);//10 20
    *p=1;
    *q=2;
    //a=1;//error: assignment of read-only variable ‘a’
    //b=2;//error: assignment of read-only variable ‘b’
    printf("%d %d\n",a,b);//1 2

a的值

a的地址

p的地址

a

&a

&p

*p

p

q

**q

*q

验证:

#include 
#include 
int main(int argc, char const *argv[])
{
    int a=10;
    int *p=&a;
    int **q=&p;
    printf("%d %d %d\n",a,*p,**q);
    printf("%p %p %p\n",&a,p,*q);
    printf("%p %p\n",&p,q);
    return 0;
}

结果:

10 10 10
0xbf9839b0 0xbf9839b0 0xbf9839b0
0xbf9839b4 0xbf9839b4

(2) 修饰指针指向的内容

也就是修饰*p,此时指针指向的内容不能改变,但是指向可以改变。

const int *p;
int const *p;
#include 
#include 
int main(int argc, char const *argv[])
{
    int a=10;
    int b=20;
    int const *p=&a;
    const int *q=&b;
    printf("%d %d\n",a,b);//10 20
    //*p=1;//*p只读不可以被更改
    //*q=2;//*q只读不可以被更改
    p=q;
    printf("%d %d\n",*p,*q);//20 20
    return 0;
}

(3) 修饰指针指向

int *const p;

此时const修饰p,指针指向不能被更改,但是指向的内容可以被更改。

#include 
#include 
int main(int argc, char const *argv[])
{
    int a=10;
    int *const p=&a;
    printf("%d\n",*p);
    //p=NULL;//error: assignment of read-only variable ‘p’
    *p=20;
    printf("%d\n",*p);
    return 0;
}

4.2 void

(1) 不允许修饰普通变量:void a;//错误

(2) 可以修饰指针:void *p;

此时p是一个任意类型的指针

使用场景:函数参数或函数返回值。

注意:通过void类型修饰的指针进行取内容时,需要进行强制转换。

转换方式:(int *)p 为右值

int a=100;
void *p=&a;
int *q=(int *)p;
printf("%d %d\n",*(int *)p,*q);

标签:int,C语言,char,++,printf,include,指针
From: https://blog.51cto.com/u_14458591/6400784

相关文章

  • C语言——运算符和表达式
    所谓表达式就是指由运算符、运算量和标点符号组成的有效序列,其目的是说明一个计算过程。表达式可以独立成语句:表达式;运算符按功能分为:算术运算、赋值运算、关系运算、逻辑运算、位运算以及其他运算符1.算术运算符:+-*/%++–(1)/:整数相除,向下取整。inta=3/2;floatb=3/2;fl......
  • C++面试八股文:C++中指针、引用、解引用和取地址有什么不同?
    某日小二参加XXX科技公司的C++工程师开发岗位2面:面试官:指针、引用、解引用和取地址是C++中的重要概念,请问它们在语法和语义上有所不同?小二:指针是一个变量,它存储了一个内存地址。小二:引用是一个别名,它允许使用一个变量的多个名称来访问同一个内存位置。小二:解引用是指使用*运......
  • 二级指针内存模型
    二级指针做输出模型#define_CRT_SECURE_NO_WARNINGS#include<stdlib.h>#include<string.h>#include<stdio.h>//指针做输出:被调用函数分配内存-----OK//指针做输入:主调用函数分配内存//求文件中的两段话的长度intgetMem(char**myp1,int*mylen1,char**myp2,in......
  • C语言数组
    数组概念在C语言中,数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。从内存角度,是一片连续的内存空间数组初始化://在编译时明确指定......
  • c语言结构体
    定义结构体变量structStudent{char*name;intage;intscore;};voidmain(){structStudentst1;system("pause");}#include<stdlib.h>#include<string.h>#include<stdio.h>typedefstructStudent{char*nam......
  • C语言链表
    #define_CRT_SECURE_NO_WARNINGS#include<stdlib.h>#include<string.h>#include<stdio.h>/*structTeacher{charname[64];intid;char*p;char**p2;};typedefstructTeacherTeacher;*/typedefstructStudent......
  • 二级指针与const
    二维数组分配:#include<iostream>intmain(){introws=3;intcols=4;//使用二级指针创建一个动态分配的二维数组int**array=newint*[rows];for(inti=0;i<rows;i++){array[i]=newint[cols];}//给数组赋值intcount=0;......
  • 单元测试及C语言的几个例子
     一、单元测试介绍单元测试是软件开发中的一种测试方式,它主要是对代码中最小可测试单元进行检查和验证。通常来说,单元测试的实施应该在整个软件开发周期的早期就开始,最好是在代码编写过程中就边写边测试,以及在执行集成和系统测试之前启动。下面是单元测试的详解:单元测试的目的:单元......
  • 双指针算法模板和一些题目
    什么是同向双指针?什么是相向双指针?双指针的鼻祖题——两数之和TwoSum链表上的快慢指针算法快速排序&归并排序 同向双指针•相向双指针•几乎所有TwoSum变种•Partition•QuickSelect•分成两个部分•分成三个部分•一些你没听过的(但是面试会考的)......
  • Linux系统下C语言的编程技巧
    Linux系统能够为人们提供更加安全实用的效果,保证计算机系统能够稳定的运行。利用Linux系统下首先要进行C语言的编程,掌握编程的技巧能够更好的发挥计算机的作用。如何掌握Linux系统下计算机C语言的编程技巧是计算机发展的关键要素。本文对Linux系统下计算机C语言的编程技巧进行相......