c语言指针

数组,指针,函数

橙三吉。 提交于 2019-11-29 17:37:33
  学c语言就知道数组、指针在c中有着特殊的地位。而且是必须掌握的一项知识,学会它会让你受益无穷。   一、数组   1、数组:室友一系列相同元素构成的。它连续的存储在内存中。   2、数组的声明:     格式: 类型 数组名 [元素个数];     例 : int myarray[10];     注意:在c99之前不允许出现元素个数为变量的情况。     例:       int n = 10;       int myarray[n]; // C99之前不允许(这种声明方式不允许被初始化)   3、数组的初始化:     int myarray[] = {1,2,3,4,5}; // 正确,这种情况下元素个数可以省略。     int myarray [10] = {1,2,3,4,5,6,7,8,9,0}; // 一般情况,元素和元素中间用 “,”分割     int myarray [10] = {1,2,3}; // 只初始化前三个元素。   int myarray [10] = {[4] = 4,[6] = 6}; //第5个元素个第6个员被初始化,其他元素都为0。 int n = 10; int myarray [n] = {1,2,3,4,5,6,7,8,9,0}; //错误 。C99之后允许变量作为数组的元素个数,但是不允许初始化这种声明。    

C语言之指针

痴心易碎 提交于 2019-11-29 17:37:27
一、指针简介   一般来说,指针是一个其数值为地址的变量(或者是一个数据对象)。   例: int a = 8;      int *b = &a;             由图可以看出,变量a代表的是地址ffc1,而地址ffc1 中存放的是常量8;指针变量b代表的是地址ffc2,而ffc2中处存放的是变量a的地址(即ffc1)。 来源: https://www.cnblogs.com/yuanyongbin/p/7801464.html

未初始化指针问题

让人想犯罪 __ 提交于 2019-11-29 17:29:05
《C和指针》书上说 int *a ... *a = 12 这样写声明一个变量,但未对指针初始化 如果指针是函数的形参,比如 void func(int *a) { (* a) = 12;//这样操作有无问题? } ======================= 楼主,你应该理解清楚什么是指针:通俗的讲,指针是一个地址,指针的初始化就是让指针指向一个确定的地址。*是指针的解引用符,意思是取指针指向的地址里的数据。 因此,int a; int *p = &a; // 这里是初始化,表示的是指针初始化为a的地址,实际相当于 int *p; p = &a; *p = 10; // 这是表示对指针解引用,想p所指向的地址写入10 第2个是关于函数调用,一个函数在那里,并不会自己运行,只有你去调用它它才会运行。在函数调用发生时,C语言实际做的是用实际参数代替形参。 int *p; func(p); // 在这里(函数调用)的时候,实际相当于有如下过程:int *a; a = p;(实参代替形参); *a = 10; 因此,这样操作是否有问题,关键在于p(实参)本身是否有问题。如果p本身指向了一个确切的地址,则a=p也使a(形参)实际指向了一个确切的地址,如果p本身没初始化,那么a = p 也使a实际指向了一个未初始化的地址。 来源: https://my.oschina.net/u

内存分配(全)

无人久伴 提交于 2019-11-29 17:24:58
malloc与free是C/C++的 标准库函数 ,new/delete是C++的 关键字 。它们都可用于申请动态内存和释放内存。 使用动态内存很明显的好处就是:不需要预先分配存储空间且分配的空间可以根据程序的需要扩大或缩小,这样可以有效的使用内存空间。 对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象的消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。 1、malloc和free #include < malloc.h > #include <alloc.h> #include < stdlib.h > 三者其中一个就行。 void *malloc(size_t size);//返回指向内存块首地址的指针,指针类型是void*,所以后续需要转换 void free(void *pointer); 使用示例: int *p=(int *)malloc(100); //指向整型的指针p指向一个大小为100字节的内存的地址, int *p=(int *)malloc(25*sizeof(int)); //指向整型的指针p指向一个25个int整型空间的地址 /*如果分配失败了,会返回一个空指针

数组指针和指针数组,行指针列指针

爷,独闯天下 提交于 2019-11-29 16:42:44
首先,需要理解一下 数组指针 和 指针数组 这两个名词: “数组指针”和“指针数组”,只要在名词中间加上“的”这个字,就知道中心了 数组的指针: 是一个指针 , 指向数组的指针 。 指针的数组: 是一个数组 , 装着指针的数组 。 还有一件事需要牢记: 优先级:()> [ ] > * (*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n, 这是“数组的指针”,即数组指针; *p[n]:根据优先级,先看[],则p是一个数组,再结合*,这个数组的元素是指针类型,共n个元素, 这是“指针的数组”,即指针数组。 根据上面两个分析,可以看出,p是什么,则词组的中心词就是什么,即数组“指针”和指针“数组”。 综上所诉: (*p)[n]:数组指针:是指针——指向数组的指针。 *p[n]:指针数组:是数组——装着指针的数组。 数组指针是一个指针变量,占有内存中一个指针的存储空间; 指针数组是多个指针变量,以数组的形式存储在内存中,占有多个指针的存储空间。 接下来讲解行指针与列指针: 这两种特殊的指针是针对C语言中的二维数组来说的。 二维数组,可以理解为数组的数组 所以对于一个数组: int a [ 2 ] [ 3 ] = { 1 , 2 , 3 , 4 , 5 , 6 } ; 他相当于:数组成员为一维数组的一维数组,这就是二维数组 int a [ 2 ]

二级指针底层实现

坚强是说给别人听的谎言 提交于 2019-11-29 16:17:28
Pointers to Pointers,即二级指针。 一级指针和二级指针的值都是指向一个内存单元: 一级指针指向的内存单元存放的是源变量的值, 二级指针指向的内存单元存放的是一级指针的地址。 下面,我们通过如下代码展示二级指针的底层实现: #include <stdio.h> int main(){ int a = 777; int* b = &a; int** c = &b; *b = 888; **c = 999; printf("a=%d\n", a); return 0; } 假设: 栈的基地址为0,即rbp寄存器指向0; 栈的指针寄存器rsp指向地址为-32。 则,c语言语句 **c = 999 的底层实现过程如下图所示: 底层实现中,汇编语言首先找到c的值,通过c的值找到b的值,通过b的值找到a,并赋值999给a。 具体汇编代码如下: .file "hlist.c" .text .section .rodata .LC0: .string "a=%d\n" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp movq %rsp, %rbp subq $32, %rsp // rsp 减去 32 movq %fs:40, %rax movq %rax, -8(

C++中的强制类型转换

做~自己de王妃 提交于 2019-11-29 16:05:36
在C语言中,强制类型转换的方式为(Type)Expression,另外还有一种现在已经不用的旧式写法Type(Expression),这两种方式是等价的。 但是,C语言的强制类型转换方式存在一些问题: 过于粗暴,可以在任意类型之间进行转换,编译器很难判断其正确性 难于定位,在源代码中无法快速定位所有使用强制类型转换的语句 然而,强制类型转换在实际工程中几乎是不可避免的,为此C++将强制类型转换分为4种不同的类型,以提供更加安全可靠的转换。 强制类型转换 说 明 static_cast 用于 基本类型之间、有继承关系的类对象之间、类指针之间 的转换 不能用于 基本类型指针之间 的转换 const_cast 用于 去除变量的只读属性 强制转换的 目标类型必须是指针或引用 reinterpret_cast 用于 指针类型之间、整数和指针类型之间 的转换 dynamic_cast 用于 有继承关系的类指针之间、有交叉关系的类指针之间 的转换 具有类型检查的功能 需要虚函数的支持 C++提供的4种强制类型转换以关键字的方式出现,使用语法为: xxx_cast<Target Type>(Expression) 。 #include <stdio.h> void static_cast_demo() { int i = 0x12345; char c = 'c'; int *pi = &i;

数组

倖福魔咒の 提交于 2019-11-29 15:55:25
一维数组 一维数组初始化 在创建数组时,我们必须定义数组的类型和大小,数组的大小不能为0,数组中的元素类型都是相同的。 数组长度必须是固定的,必须为常量或常量表达式,不能使用变量进行初始化。 一维数组初始化 完整初始化: int arr[3] = {1, 2, 3}; 不完整初始化: int arr[3] = {1, 2}; 自动计算数组长度初始化: int arr[] = {1, 2, 3}; 注意: 静态初始化缺省情况将数组元素自动设置为0,自动初始化缺省情况下是未初始化的。 数组初始化元素的个数不允许超过数组长度: int a[3] = {1,2,3,4}; // 不合法 字符数组的初始化 最笨拙的方式: char message[] = { 'h','e','l','l','o',0 }; 快速初始化方式: char message[] = "hello"; 这种初始化方式与上面的初始化方式是等效的,并且默认会在末尾 '\0' 。 上面都是字符数组初始化的基本方式,如果要初始化字符串常量,则采用: char *message = "hello"; 。 初始化字符数组和字符串常量的区别,可以表示如下: 作符返回一个指向数组的指针,而不是一个指向数组第一个元素的指针的指针。 注意: 数组名的值是一个指针常量,不能修改它的值。 int a[5]; int b[5]; a = b;

指针

*爱你&永不变心* 提交于 2019-11-29 15:51:20
内存和地址 内存其实就是一组有序字节组成的数组,数组中,每个字节大小固定,都是 8bit。对这些连续的字节从 0 开始进行编号,每个字节都有唯一的一个编号,这个编号就是内存地址。示意如下图: 指针变量保存的就是这些编号,也即内存地址。 地址与内容 我们只要知道内存地址,就可以访问这个地址的值,但是这种方法实在笨拙,于是便用变量名来代替地址: 名字与内存之间的关联仅仅只是编译器实现的,采用变量名的方式能够方便的记住地址,但是硬件仍然通过地址访问内存位置。 值和类型 考虑下面的32位值: ‭01100111011011000110111101100010‬ 对于这些位的解释可以分为很多种: 类型 值 1个32位数 1735159650 2个16位数 26476和28514 4个字符 glob 浮点数 1.116533e24 机器指令 beg.+110和ble.+102 可见: 不能简单地通过检查一个值的位来判断值的类型,而应该根据它的使用方式来判断 。 使用指针的优势 在C语言中,指针的使用非常广泛,因为使用指针往往可以生成更高效、更紧凑的代码。总的来说,使用指针有如下好处: 指针的使用使得不同区域的代码可以轻易的共享内存数据,这样可以使程序更为快速高效。 C语言中一些复杂的数据结构往往需要使用指针来构建,如链表、二叉树等。 C语言是传值调用,而有些操作传值调用是无法完成的

c语言中函数指针和指针函数

独自空忆成欢 提交于 2019-11-29 14:10:49
一.什么是函数指针:   函数指针本质上也是指针,我们所写函数代码在内存中会被分配一段专门的储存空间,这段储存空间的地址就是函数的地址,既然是地址,就可以用指针去表示,自然就有了函数指针。 二.函数指针的用法:   1.首先明确函数指针怎么申明。形如:返回值类型 (*变量名)(参数类型1,参数类型2,。。。)   例如 int (*p) (int,int)   2.我们还需要了解如何通过指针调用函数。 (*p)(3,5);      3.如何给该类型的指针赋值:   非常简单,直接将函数名赋给指针即可,因为函数名即为函数的首地址,这样的赋值顺理成章。   例如: int Func(int x); /*声明一个函数*/ int (*p) (int x); /*定义一个函数指针*/ p = Func; /*将Func函数的首地址赋给指针变量p*/   4.请看一下完整的用法:   # include <stdio.h> int Max(int, int); int main(void) { int(*p)(int, int); int a, b, c; p = Max; printf("please enter a and b:"); scanf("%d%d", &a, &b); c = (*p)(a, b); //通过函数指针调用Max函数 printf("a = %d\nb =