数组
#define N 10 int a[N]; for(int i=0;i<N;i++) { a[i] = 0; } //初始化,没有被初始化到的数组下标就被设置为0 int a[10] = {1,2,3,4,5}; //等价于 int a[10] = {1,2,3,4,5,0,0,0,0,0}; //也可以写成入如下形式相当于把整个数组全部赋值为0 int a[10]={0}; //C99中可以指定对某个元素下标赋值,剩余的就被赋值为0 int a[15] = {[2]=11, [9]=33, [14]= 99}; //对数组使用sizeof运算符 int a[10]; sizeof(a); //结果就是40 //sizeof 返回的是无符号的整形size_t,无符号和有符号之间运算会有危险, //最好使用强制转型 //数组清零 #define SIZE ( (int)(sizeof(a)/sizeof(a[0])) ) //多维数组初始化 int m[5][9] = {{1,2,3,4,5,6}, {2,3,54,5,6}, {4,5,6,7,8}, {3,5,6,7,11}}; //也可以省略外面的一层大括号 int m[5][9] : {1,2,3,4,5,6, {2,3,54,5,6, {4,5,6,7,8, {3,5,6,7,11}; //常量数组 const char hex_chars[] = {'0','1','2','3'}; //C99中也可以对多维数字进行指定下标的初始化 //C99还支持变长数组
指针
//定义一个指针 int *p; //每个指针变量只能指向一种特定的类型 int *p; double *d; char *r; //赋值和访问 &运算符是获取一个变量的地址值, *那个运算符是间接寻址 int i, *p; i = 10; p = &i; printf("%d",*p); //这样的赋值是错误的 int i, *p; i = 10; *p = &i; //这里是将 i的地址赋予p指向的内容,所以是错误的 //*p是指针指向的内容,是一个具体的值,p才表示一个地址,所以 //应该是 p = &i; 将i的地址赋予指针p才是正确的 //指针作为返回值 int *max(int *a, int *b) { if(*a > *b) { return a; } return b; } //注意,永远不要返回指向局部变量的指针 int *f(void) { int i; return &i; } //一旦函数f返回,变量i就不存在了,所以变量i的指针将是无效的,有的编译器会 //在这种情况下给出类似"function returns address of local variable"的 //警告 //未初始化的指针变量指向的是一个不确定的内存地址值 //用const保护参数,也就是指针指向的内容是常量不可改变,但指针内容本身是 //可以被改变的,也可以包含指针本身,还可以包含指针本身和指针指向的内容 //第一种情况,保护指针指向的内容,此时指针本身可以改变 int number = 100; const int *p; //*p = 0; p = &number; //第二种情况,保护指针本身,指针指向的内容可以被改变 int *const p2; *p2 = 0; //p2 = &number; //第三种情况,包含指针本身,以及指针指向的内容 const int *const p3; //*p3 = 0; //p3 = &number;
指针和数组
//定义指针,指针p指向a数组的第一个元素 int a[10], *p; p = &a[0] //设置数组a有10个元素 p = &a[2]; //指向数组a的第三个元素 int *q = p+3; //指向数组a的第六个元素,也就是a[5] p -= 4; //指向数组a的第二个元素,也就是a[1] //两个指针之间可以相减,但是两个指针必须都指向同一个数组,因为比较的是内存 //地址,如果两个数组指向的是两个不同的数组,最后计算出来的结果可能是未知的 //内存
*运算符和 ++运算符(++运算符优先级高于*)
表达式 | 含义 |
*p++或者*(p++) | 先自增p的值,然后再获得*p |
(*p)++ | 自增前的表达式是*P,以后再自增*p |
*++p或*(++p) | 先自增p,自增表达式的值是*p |
++*p或++(*p) | 先自增*p,那个自增后表达式的值是*p |
//用数组名做指针 int a[10]; *a = 7; //等于a[0] = 7; //也可以通过指针来修改a[1] *(a+1) = 12; //等于a[1] = 12; //遍历 for(p=&a[0]; p<a[N]; p++) { sum += *p; } //处理多维数组 int a[NUM_ROWS][NUM_COLS]; int *p; for(p=&a[0][0]; p<= &a[NUM_ROWS-1][NUM_COLS-1]; p++) { *p = 0; } //C99中的指针和变成数组
指针的高级应用
//内存分配函数,这些都是声明在<stdlib.h>头文件中 //malloc()函数 分配内存块,但是不对内存块进行初始化 //calloc()函数 分配内存块,并且对内存块进行初始化 //realloc()函数 调整先前分配的内存块大小 //空指针用表示 不指向任何地方的指针,用名为 NULL 的宏来表示 //NULL 定义在<stdlib.h>中 p = malloc(1000); if(NULL == p) { //分配失败 } //malloc函数原型,它返回的是void*类型指针,所以需要转型,这个void*就代表 //任何类型 void *malloc(size_t size); //分配字符串时需要分配n+1大小空间,因为字符串最后是\0结尾 p =(char*) malloc(n+1); //分配数组空间,注意分配时必须使用sizeof计算单个值占多少字节 int *a; a = malloc(n * sizeof(int)); //calloc函数原型,为nmemb个元素的数组分配内存空间,其中每个元素长度 //都是size个字节,如果要求的空间无效会返回空指针 void *calloc(size_t nmemb, size_t size); a = calloc(n, sizeof(int)); //realloc函数原型,其中ptr必须指向先前通过malloc,calloc,realloc的调用 //获得的内存块,size表示新尺寸可能会大于或小于原有尺寸。 void *realloc(void *ptr, size_t size);
C标准列出了几条关于realloc函数的规则
1.当扩展内存块时,realloc函数不会对添加进内存块的字节数进行初始化
2.如果realloc函数不能按要求扩大内存块,那么它会返回空指针,并且在原油的内存块中的数据不会发生改变
3.如果realloc函数调用时以空指针作为第一个实际参数,那么它的行为就像malloc函数一样
4.如果realloc函数被调用时以0作为第二个实际参数,那么它会释放掉内存。
注意:一旦realloc函数返回一定要对所有指针进行更新,因为ralloc函数可能会使内存块移动到了其他地方
//用free函数释放动态申请的内存,其原型为 void free(void *prt); //悬空指针问题 char *p = malloc(4); free(p); strcpy(p, "abc"); //此时p指向的内存已经被释放掉了,再对其修改可能会造成 //严重的错误 //结构体 struct node { int value; struct node *next; }; struct node *new_node= NULL; new_node = malloc(sizeof(struct node)); //写成这样是不对的,我们需要申请结构体大小的空间,而这样申请的是指针大小的 //空间,一个指针可能是4个字节,这样实际上就申请了4个字节 new_node = malloc(sizeof(new_node)); // ->运算符 (*new_node).value = 10; //等价于 node_new->value = 10; //指向指针的指针 char **ptr; *ptr = "abc"; //ptr是指向"abc"的地址 //指向函数的指针 //假设函数integrate的原型如下: (*f)说明f 是个指向函数的指针 double integrate(double (*f)(double), double a, double b); //也可以写成: double integrate(double f(double), double a, double b); //调用integrate时,将把一个函数名作为第一个实际参数,注意sin后面没有括号 //C编译器会产生指向函数的指针而不是产生函数调用的代码 result = integrate(sin, 0.0, PI/2); //在函数integrate中, *f 表示调用f 所指向的函数,*f 就是调用sin函数 // (*f)(x) 和f(x)都是一样的,但是用(*f)(x)更好,说明是f是指向函数的指针 //C函数库中的qsort函数原型 void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)); //base是指向数组中的第一个元素,nmemb是要排序元素的数量,size是每个 //数组元素的大小,compar是指向比较函数的指针 int compare_parts(const void *p, const void *q) { const struct part *p1 = p; const struct part *p2 = q; if(p1->number < p2->number) { return -1; } else if(p1->number == p2->number) { return 0; } return 1; } //还可以写成: int compare_parts(const void *p, const void *q) { return ((struct part*)p)->number - ((struct part*)q)->number; } //指向函数的指针,可以指向任何参数是int,返回void类型的函数 void (*pf) (int); void fun(int x); pf = fun; //让pf指向函数fun,注意fun前面不需要加 & pf(100); //受限指针 int * restrict p; //灵活数组成员 struct vstring{ int len; char chars[N]; }; //这里N表示一个字符串最大长度的宏,但是分配最大长度会导致浪费,于是采用 //如下方式申明chars长度 struct vstring{ int len; char chars[1]; }; struct vstring * str = malloc(sizeof(struct vstring) +n-1); //这样就看以达到目的了,并且内存不会浪费,这样叫 struct hack 技术 //C99支持灵活数组成员,当结构体最后一个是数组时可以省略长度 struct vstring{ int len; char chars[]; };
定义NULL为
#define NULL (void*)0;
如果把NULL 定义为0,那么把NULL赋给整型变量index是合法的,但是把NULL定义为(void*)0 则表示把指针赋值给了整型变量
将malloc函数的值类型强制转换没有任何好处,这是来自于经典C的习惯。
参考:
相关推荐
在C语言中,数组名和指针之间存在微妙且重要的区别,这往往让初学者感到困惑。虽然在某些上下文中,它们看似可以互换使用,但深入理解它们的本质差异对于编写高效、安全的代码至关重要。 ### 一、数组名与指针的...
在C语言中,数组和指针是两个非常重要的概念,它们之间既有明显的区别,也有紧密的联系。数组是一种数据结构,而指针则是一种特殊的数据类型,用于存储内存地址。理解这两者的差异和关联对于深入学习C语言至关重要。...
### C语言数组、指针与编程技巧 #### 一、数组的基本概念与使用方法 **数组**是一种数据结构,用于...以上是对C语言中数组、指针以及一些编程技巧的详细介绍,希望能够帮助读者更好地理解和掌握这些重要的编程概念。
在编程中,数组和指针是两种非常基础且重要的概念,它们在处理数据时起着核心作用。数组是一组相同类型的元素的集合,通过索引来访问每个元素。指针则是一个变量,它存储的是内存地址,这个地址通常指向一个变量或...
在C语言中,数组和指针是编程时非常重要的概念,尤其在处理大量数据或实现高效算法时。在第四章“数组和指针”中,我们主要探讨了以下几个知识点: 1. **数组的概念**: 数组是一组相同类型的变量,它们按照下标...
"C语言函数、数组、指针练习题" 1. 选择题1:C程序的执行是从main函数开始执行的。因此,正确答案是A。 2. 选择题2:使指针p1指向变量a,...通过这些练习题,我们可以熟悉C语言的语法和使用方法,从而提高编程能力。
【C语言程序设计:数组、指针与字符串】 在C语言中,数组是编程...综上所述,C语言的数组和指针是编程的基础,它们提供了高效地处理和操纵内存中数据的能力。理解和熟练运用这些概念对于编写高效的C语言程序至关重要。
掌握C语言的关键在于理解和运用指针、数组、结构体和链表等核心概念。 **一、学习编程语言的一些建议** 1. **多动手**:编程实践是学习编程的最有效方式。通过编写和调试程序,可以深入理解语言的特性和工作原理。...
本项目利用C语言编程,通过数组的指针来实现对LED流水灯的控制,这涉及到C语言的基础语法、指针操作以及系统相关编程。 首先,我们要理解C语言中的指针。指针是C语言的一个重要特性,它存储的是内存地址,可以用来...
本课程聚焦于C语言中的核心概念,包括数组、指针和结构体,这些都是理解和编写C程序的关键。 首先,让我们深入探讨数组。数组是C语言中存储多个相同类型数据的一种方式。你可以将其想象为一个连续的内存空间,每个...
本资料包包含46个C语言源文件,专门探讨数组的运算,特别是各种排序算法的实现,这对于理解和掌握C语言的数组操作至关重要。下面我们将详细讲解数组在C语言中的概念、操作以及常见的数组运算实例。 1. **数组定义与...
- **数组指针** (`int (*pa)[4][3];`):可以用来访问整个数组。 - **行指针** (`int (*pr)[3];`):可以用来访问数组中的某一行。 - **列指针** (`int *p;`):可以用来访问数组中的某个元素。 对于二维数组`int a[4]...
本主题将深入探讨数组指针和函数指针的应用,通过提供的源代码实例,我们可以更好地理解这两种概念的实用性和灵活性。 首先,数组在C/C++中本质上是一段连续的内存空间,存储相同类型的数据。数组名通常被视为指向...
在C语言中,定义一维数组的语法是通过指定元素类型、数组名和元素个数来实现。例如,int a[10]定义了一个名为a的整型数组,它包含10个整数。 数组的引用需要在定义之后进行,并且只能逐个引用数组元素,不能一次...
C语言编程100例算法指针数组 本资源是一个C语言编程的集合,共有五个程序,每个程序都解决了一个...这五个程序展示了C语言编程的多样性和灵活性,並展示了数组、指针、循环语句和条件语句等基本语法和数据结构的应用。
数组和指针是C语言中非常重要的概念。数组提供了存储一系列相同类型数据的有效方式,而指针则提供了灵活地访问和操作内存的能力。理解这两个概念对于掌握C语言至关重要,并且对于编写高效、安全的程序非常重要。通过...
总结来说,数组指针`int (*p)[n]`是一个指向数组的指针,而指针数组`int *p[n]`是一个包含`n`个指针的数组。两者在声明、赋值和使用方式上都有所不同。理解这些区别对于编写高效、无误的C/C++代码至关重要。在实际...
C语言是一种基础且强大的编程语言,它以其简洁的语法和高效执行著称。在C语言中,数组是一种非常重要的数据结构,它允许我们存储多个相同类型的数据在一个单一的变量中。这个“c语言习题(数组).zip”文件很可能...
本资源包“c语言之语法代码集”聚焦于C语言的核心语法元素,包括文件操作、数组、指针、结构体和共同体,这些都是C语言编程的基础和核心。 1. **文件操作**:在C语言中,文件操作是通过标准库函数如`fopen`, `...