您的位置:首页 > 汽车 > 时评 > 楼盘网官网_搜索关键词网站_唐山网站建设方案优化_百度如何免费推广

楼盘网官网_搜索关键词网站_唐山网站建设方案优化_百度如何免费推广

2025/5/3 12:49:24 来源:https://blog.csdn.net/m0_74794884/article/details/138977478  浏览:    关键词:楼盘网官网_搜索关键词网站_唐山网站建设方案优化_百度如何免费推广
楼盘网官网_搜索关键词网站_唐山网站建设方案优化_百度如何免费推广

1.1数组

数组由数据类型相同的一系列元素组成。

char code[20];
int arr[12];

1.1.1初始化数组

只存储单个值的变量也称为标量变量

初始化:int powers[8]={1,2,3,4,5,6,7,8};

/*day_mon1.c --打印每个月的天数*/
#include <stdio.h>
#define MONTHS 12
int main()
{int days[MONTHS] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int index;for(index = 0; index < MONTHS; index++)printf("%d月有%d天", index, days[index]);return 0;
}

在使用数组之前,必须赋初值。

部分初始化数组,剩余元素会被初始化为0;初始化数组超过数组元素个数,则会出现错误。

省略方括号中的数字,编译器会自动匹配数组大小和初始化列表项数。

1.1.2数组元素赋值

赋值:循环赋值

int counter, evens[SIZE]
for(counter = 0; counter < SIZE; counter++)
{evens[counter] = 2 * counter;
}

声明数组后,借助数组下标给数组元素赋值。

不允许把数组作为一个单元赋给另一个数组,除了初始化以外不允许在其他地方使用花括号列表形式赋值。

1.1.3数组边界

在使用数组时,要防止数组下标越界,必须确保下标是有效的。在编译器中,不会检查数组下标是否得当,数组越界会导致程序改变其他变量的值或者使程序中断。数组的编号从0开始,最好在声明数组时使用符号常量来表示数组的大小。

1.1.4指定数组大小

在C99之前,声明数组时只允许使用整型常量表达式,C99后,允许使用变长数组(VLA)

int array[4];        //整型常量表达式

int array[m];        //C99后允许

1.2多维数组

/*计算每年总降水量、年平均降水量和5年中每月的平均降水量*/
#include <stdio.h>
#define MONTHS 12	//一年的月份
#define YEARS 5		//年数
int main(void)
{//用2010~2014年的降水量数据初始化数组const float rain[YEARS][MONTHS] ={{4.3, 4.3, 4.3, 3.0, 2.0, 1.2, 0.2, 0.2, 0.4, 2.4, 3.5, 6.6},{8.5, 8.2, 1.2, 1.6, 2.4, 0.0, 5.2, 0.9, 0.3, 0.9, 1.4, 7.3},{9.1, 8.5, 6.7, 4.3, 2.1, 0.8, 0.2, 0.2, 1.1, 2.3, 6.1, 6.4},{7.6, 5.6, 3.8, 2.8, 3.8, 0.2, 0.0, 0.0, 0.0, 1.3, 2.6, 5.2}};int year, month;float subtot, total;printf("YEAR RAINFALL (inches)\n");for (year = 0, total = 0; year < YEARS; year++){for (month = 0, subtot = 0; month < MONTHS; month++)subtot += rain[year][month];printf("%5d %15.1f\n", 2010 + year, subtot);total += subtot;	//5年的总降水量}printf("\nThe yearly average is %.1f inches.\n\n", total / YEARS);printf("MONTHLY AVERAGES:\n\n");printf("Jan Feb Mar Apr May Jun Jul Aug Sep Oct ");printf("Nov Dec\n");for (month = 0; month < MONTHS; month++){//每个月,5年的总降水量for (year = 0, subtot = 0; year < YEARS; year++)subtot += rain[year][month];printf("%4.1f ", subtot / YEARS);}printf("\n");return 0;
}

程序输出:

使用两个嵌套for循环。第一个嵌套for循环的内层循环,在year不变的情况下,遍历month计算某年降水量,外层循环在month不变的情况下,遍历year计算5年总降水量。

嵌套循环常用来处理二维数组,一个循环处理第一个下标,一个处理第二个下标。

1.2.1初始化二维数组

const float rain[YEARS][MONTHS] =
    {
        {4.3, 4.3, 4.3, 3.0, 2.0, 1.2, 0.2, 0.2, 0.4, 2.4, 3.5, 6.6},
        {8.5, 8.2, 1.2, 1.6, 2.4, 0.0, 5.2, 0.9, 0.3, 0.9, 1.4, 7.3},
        {9.1, 8.5, 6.7, 4.3, 2.1, 0.8, 0.2, 0.2, 1.1, 2.3, 6.1, 6.4},
        {7.6, 5.6, 3.8, 2.8, 3.8, 0.2, 0.0, 0.0, 0.0, 1.3, 2.6, 5.2}
    };

每个数值列表都用花括号括起来,如果一个列表只有10个数,只会初始化数组的第一行10个元素,后面的元素将默认初始化为0。初始化超过时,会出错。初始化可省略内部花括号。

1.2.2其他多维数组

int box[10][20][30];

三维数组,将10个二维数组堆叠起来。处理三维数组要使用三层嵌套循环。

……

1.3指针和数组

指针提供一种以符号形式使用地址的方法。指针能有效地处理数组,数组表示法其实是变相的使用指针。 

//pnt_add.c	--指针地址
#include <stdio.h>
#define SIZE 4int main()
{short dates[SIZE];short* pti;short index;double bills[SIZE];double* ptf;pti = dates;	//把数组地址赋给指针ptf = bills;printf("%23s %15s\n", "short", "double");for (index = 0; index < SIZE; index++)printf("pointers + %d: %10p %10p\n", index, pti + index, ptf + index);return 0;
}

该示例中,第二行打印的是数组开始的地址,下一行打印的是指针加1后的地址。

在C语言中,指针加1指的是增加一个存储单元。于数组而言,加1后的地址是下一个元素的地址,而不是下一个字节的地址。这是为什么必须声明指针所指向对象类型原因之一。

注:

1.指针的值是它所指向对象的地址。

2.在指针前使用*可以得到该指针所指向对象的值。

3.指针加1,指针的值递增它所指向类型的大小。

1.4函数、数组和指针

编写一个处理数组的函数,函数返回数组中所有元素的和,待处理名为marbles的int类型数组。

数组名是该数组首元素的地址,所以实际参数marbles是一个存储int地址,把它赋值给一个指针形式参数,该参数是一个指向int的指针:

int sum (int *ar);        //函数原型

注:该函数原型只获得了数组首元素地址,但是没有包含数组元素个数信息。使用以下两个方法:

(1)int sum(int *ar)        //函数定义

         {

                int i;

                int total = 0;

                for(i = 0; i < 10; i++)        //数组有10个元素

                        total += ar[i];           //ar[i]和*(ar + i)相同

                return total;

         }

该方法限制了函数数组元素

(2)int sum(int *ar , int n)

        {

                int i;

                int total = 0;

                for(i = 0; i < n; i++)        //数组有10个元素

                        total += ar[i];           //ar[i]和*(ar + i)相同

                return total;

          }

第1个形参表示数组地址和数据类型,第2个形参表示数组中的个数。

注:

数组名是该数组首元素的地址,作为实际参数的数组名要求形式参数是一个与之匹配的指针。

下面函数原型都是等价的:

int sum(int *ar, int n);

int sum(int *, int);

int sum(int ar[], int n);

int sum(int [], int n);

下列函数定义等价:

int sum(int *ar, int n)

{}

int sum(int ar[], int n)

{}

程序输出如下: 

//sum_arr1.c --数组元素之和
#include <stdio.h>
#define SIZE 10int sum(int ar[], int n);int main()
{int marbles[SIZE] = { 20,10,5,39,4,16,19,26,31,20 };long answer;answer = sum(marbles, SIZE);printf("The total number of marbles is %d.\n", answer);printf("The size of marbles is %zd byte.\n", sizeof marbles);return 0;
}int sum(int ar[], int n)
{int i;int total = 0;for (i = 0; i < n; i++)total += ar[i];printf("The size of ar is %zd bytes.\n", sizeof ar);return total;
}

1.4.1 使用指针形参

函数要处理数值必须知道何时开始,何时结束。一种方法是使用一个指针形参标识数组的开始,用一个整数形参表明待处理数组的元素个数;另一种方法是直接传递两个指针

/*sum_arr2.c --数组元素之和*/
#include <stdio.h>
#define SIZE 10int sump(int* start, int* end);int main(void)
{int marbles[SIZE] = { 20,10,5,39,4,16,19,26,31,20 };long answer;answer = sump(marbles, marbles + SIZE);printf("The total number of marbles of marbles is %ld.\n", answer);return 0;
}//指针算法
int sump(int* start, int* end)
{int total = 0;while (start < end){total += *start;start++;}return total;
}

代码解析:指针start开始指向marbles数组的首元素,则,total += *start表示把首元素加给total然后start++递增指针变量start,使其指向数组的下一个元素,因为start是指向int的指针,start+1相当于递增int类型的大小。

1.5 指针操作

//ptr_ops.c --指针操作
#include <stdio.h>int main(void){int urn[5] = { 100,200,300,400,500 };int* ptr1, * ptr2, * ptr3;ptr1 = urn;		//把一个地址赋给指针ptr2 = &urn[2];	//把一个地址赋给指针printf("pointer value, dereferenced pointer, pointer address:\n");printf("ptr1 = %p, *ptr1 = %d, &ptr1 = %p\n", ptr1, *ptr1, &ptr1);//指针加法ptr3 = ptr1 + 4;printf("\nadding an int to a pointer: \n");printf("ptr1 + 4 = %p,*(ptr1 + 4) = %d\n", ptr1 + 4, *(ptr1 + 4));ptr1++;		//递增指针printf("\nvalues after ptr1++: \n");printf("ptr1 = %p,*ptr1 = %d, &ptr1 = %p\n", ptr1, *ptr1, &ptr1);ptr2--;		//递减指针printf("\nvalues after --ptr2: \n");printf("ptr2 = %p,*ptr2 = %d, &ptr2 = %p\n", ptr2, *ptr2, &ptr2);--ptr1;		//恢复初始值++ptr2;		//恢复初始值printf("\nPointers reset to original value: \n");printf("ptr1 = %p, ptr2 = %p\n", ptr1, ptr2);//一个指针减去另一个指针printf("\nsubtracting one pointer from another: \n");printf("ptr2 = %p, ptr1 = %p, ptr2 - ptr1 = %td\n", ptr2, ptr1, ptr2 - ptr1);//一个指针减去一个整数printf("\nsubtracting an int from a pointer: \n");printf("ptr3 = %p, ptr3 - 2 = %p\n", ptr3, ptr3 - 2);return 0;
}

程序结果:

解析:

(1)赋值:可以把地址赋给指针,如数组名,带地址运算符(&)的变量名、另一个指针进行赋值。例:把urn数组的首地址赋给ptr1;注:地址和指针类型兼容,不可进行类型转换。

(2)解引用:*运算符给出指针指向地址上存储的值。如*ptr1的初值是100,该值存储在编号为000000BA93B4F4D8地址上。

(3)取址:&给出指针本身的地址。如:ptr1的地址编号是000000BA93B4F508,该存储单元存储的内容是000000BA93B4F4D8,即urn的地址。&ptr1是指向ptr1的指针,ptr1是指向urn[0]的指针。

(4)指针与整数相加:可以使用+把指针与整数相加,或整数与指针相加,即:整数都会和指针所指向类型的大小(以字节为单位)相乘,然后把结果与初始地址相加。如果相加结果超出了初始指针指向的数组范围,计算结果则未定义。

(5)递增指针:递增指向数组元素的指针可以让该指针移动至数组的下一个元素。如:ptr++=ptr的值+4,ptr指向urn[1]。此时,ptr1的值是000000BA93B4F4DC(数组的下一个元素地址),*ptr1的值为200(urn[1]的值),此时ptr1本身地址仍然是000000BA93B4F508。变量不会因为值发生变化就移动。

(6)指针减去一个数:指针必须是第一个操作对象,整数是第二个操作对象。整数都会和指针所指向类型的大小(以字节为单位)相乘,然后把结果与初始地址相减。如果相减结果超出了初始指针指向的数组范围,计算结果则未定义。

(7)递减指针:与递增指针相似。

(8)指针求差:求差的两个指针分别指向同一个数组的不同元素,求出两个元素的距离,单位与数组类型相同。如果指向两个数组的指针求差会得出一个值或运行错误。

(9)比较:关系运算符比较两个指针的值前提是两个指针具有相同的类型对象。

注:在递增或者递减指针时,编译器不会检查指针是否指向数组元素。

        不要解引用未初始化的指针。因为未初始化的指针其值是一个随机值。

        在创建指针时,系统只分配存储指针本身的地址,但是未分配存储数据的内存。

1.6保护数组中的数据

 在程序中,只有需要在函数中改变该数值时,才会传递指针,否则都是直接传递数据,但是,传递数组时,必须传递指针。

但是传递地址会导致一些问题,C通常按值传递数据,可以保证数据的完整性。如果函数使用原始数据的副本,就不会意外修改原始数据。

1.6.1对形式参数使用const

如果函数意图不是修改数组内容,在函数原型函数定义中声明形式参数使用const。

例:

int sum(const int arr[], int n);    //函数原型int sum(const int arr[], int n)    //函数定义
{....}

表明arr指向的数组中的内容不可被修改。此时使用const并不是要求原数组是常量,而是函数在处理数组时将其视为常量,不可更改。

1.6.2const其他内容

可以创建const数组,const指针和指向const的指针。

const int days[Months] = {31,28,31,30,31,30,31,31,30,31,30,31}; days[9] = 0;        //错误
double rates[5] = {11.1, 22.2, 33.3, 44.4, 55.5};
const double* pd = rates;    //pd指向数组首元素    不能使用pd来改变它指向的值//不论是使用指针表示法还是数组表示法,都不允许使用pd修改指向数据的值。
//
*pd = 100;    //错误
pd[2] = 1;    //错误
rate[0] = 0;    //允许,rate未被const限定
pd++;            //正确,让pd指向rates[1]
//指向const的指针通常用于函数形参,表明该函数不会使用指针改变数据
void show_array(const double* arr, int n);
//声明一个不能指向别处的指针
double* const pc = rates;pc = &rates[2];    //错误
*pc = 1;    //允许
//这个指针可以修改它所指向的值,但是不能修改指向的地址。
//既不能修改指向地址,也不能修改指向地址上的值
const double* const pc = rates;pc = &rate[2];    //不允许
*pc = 1;    //不允许

1.7指针和多维数组

1.7.1指向多维数组的指针

 如何声明一个指针变量pz指向一个二维数组?答案是pz指向一个内含两个int类型的数组,如下

        int(* pz) [2];        //int指向一个内含两个int类型值的数组

【注】使用()的原因是[]的优先级高于*

        int * pz [2];        pz先于[]结合成为一个内含两个元素的数组,*表示pz数组内含两个指针,int表示这两个指针是int类型。

1.7.2指针的兼容性

指针之间的赋值严格,不能像数值类型转换可以进行强制转换。

	int n = 5;double x;int* p1 = &n;double* pd = &x;x = n;	//隐式转换pd = p1;	//编译错误

	int* pt;int(*pa)[3];int ar1[2][3];int ar2[3][2];int** p2;	//一个指向指针的指针pt = &ar1[0][0];	//都是指向int的指针pt = ar1[0];	//都是指向int的指针pt = ar1;pa = ar1;	//都是指向内含3个int类型元素数组的指针pa = ar2;p2 = &pt;*p2 = ar2[0];p2 = ar2; 

 

pt = ar1;        //pt是指向int的值,ar1指向一个内含3个int类型元素的数组。两个指针指向不同类型,无效。

pa = ar2;        //pa是指向一个内含3个int类型元素的数组,ar2是指向一个内含2个int类型元素的数组,无效。

pa = &pt;        //p2是指向指针的指针,它指向的指针指向int,ar2是指向数组的指针,该数组含2个int类型元素,所以p2和ar2类型不同。

*p2 = ar2[0];        //*p2是指向int的指针,ar2[0]指向该数组首元素的指针,所以ar2[0]也是指向int的指针,所以二者兼容。

1.7.3函数和多维数组

编写处理二维数组的函数,通常使用数组表示法进行相关操作。

使用for循环把处理一维数组的函数应用到二维数组的每一行。

int jnk[3][4] = { {2, 4, 5, 8}, {3, 5, 6, 9}, {12, 10, 8, 6} };
int i, j;
int total = 0;
for(i = 0; i < 3; i++)total += sum(junk[i], 4);    //junk[i]是一维数组

缺点:无法记录行和列的信息。

解决方法:

声明正确类型的形参变量,正确传递数组。

        void somefunc(int (*pt)[4]);

当且仅当pt是一个函数的形参时,如下声明:

        void somefunc(int pt[][4]);        //第一个[]是空的,表明pt是一个指针

声明一个指向N维数组的指针,只能省略最左边的[]中的值

        void sum4d(int ar[][12][20][30], int rows;

第一个[]只表示这是一个指针其他[]用于描述指针所指向数据对象的类型

1.8变长数组

C99新增变长数组,允许使用变量表示数组的维度,如下:

int q = 4;
int e = 5;
double sales[q][e];    //变长数组

变长数组的限制:必须是自动存储类别,无论在函数中声明还是作为函数形参声明,都不能使用staticextern存储类别说明符,且不能在声明中初始化

C11把变长数组作为可选特性。

【注】变长数组不能改变大小

        变长数组中的“变”是指在创建数组时,可以使用变量指定数组的维度,不是指可以修改已创建数组大小。一旦创建变长数组,大小保持不变

C99/C11标准规定:可以省略原型中的形参名,但是必须用星号代替

        int sum2(int, int, int ar[*][*]);

普通C数组都是静态内存分配,即在编译时确定数组的大小,但是变长数组允许动态内存分配,说明可以在程序运行时指定数组大小

1.9复合字面量

C99新增,是除符号常量外的常量,如5是int类型字面量。

对于数组,复合字面量类似于数组初始化列表,前面是()括起来的类型名

        普通数组声明:int diva[2] = {10, 20};

        复合字面量创建和diva数组相同的匿名数组:(int [2]) {10, 20}

        int[2]就是复合字面量的类型名

        初始化有数组名的数组时可以省略数组大小,复合字面量也可以省略大小

复合字面量是匿名的,所以必须在创建的同时使用它。如:

        int * pt1;

        pt1 = (int [2]) {10, 20};

复合字面量的类型名也代表首元素的地址,所以可以把它赋给指向int指针。

#include <stdio.h>
#define COLS 4
int sum2d(const int ar[][COLS], int rows);
int sum(const int ar[], int n);
int main()
{int total1, total2, total3;int* pt1;int (*pt2)[COLS];pt1 = (int[2]) {10, 20};pt2 = (int[2][COLS]) { {1, 2, 3, -9}, {4, 5, 6, -8} };total = sum(pt1, 2);total2 = sum2d(pt2, 2);total3 = sum((int []) {4, 4, 4, 5, 5, 5}, 6);printf("total1 = %d\n", total1);printf("total2 = %d\n", total2);printf("total3 = %d\n", total3);return 0;
}int sum(const int ar [], int n)
{int i;int total = 0;for(i = 0; i< n; i++)total +=ar[i];return total;
}int sum2d(const int ar [][COLS], int rows)
{int r;int c;for(r = 0; r < rows; r++)for(c = 0; c< COLS; c++)tot += ar[r][c];return tot;
}

输出如下:(需要支持C99的编译器)

total1 = 30 

total2 = 4

total3 = 27

复合字面量是提供只临时需要的值的一种手段。复合字面量具有块作用域。即,一旦离开定义复合字面量,程序将无法保证字面量是否存在,也就是,复合字面量的定义在最内层的花括号内

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com