指针变量(指针):能够存储地址的变量
地址运算符&:&num表示“num的地址”
间接运输符*:当*符号后面紧跟一个指针时,表示这是一个地址被存储在其中的变量
数组、指针、地址
指针操作
指针运算
*ptNum++ | 使用指针,然后给指针增1 |
*++ptNum | 在使用指针前,给指针增1 |
*ptNum– | 使用指针,然后给指针减1 |
*–ptNum | 在使用指针前,给指针减1 |
nums是数组名称,nPtr是指针(存nums[0]的地址)。
nPtr = nums;
注意:
*nPtr++ 有效
*num++ 无效
*nums 有效(nums[0])
*(nums+i) 有效(nums[i])
比较:(下面三条等价)
nPtr <= &nums[4];
nPtr <= nums + 4;
nPtr < nums + 5;
指针初始化
(下面两条顺序不能换)
int miles;
int *ptNum = &miles;
只有在声明ptNum之前miles本身被声明为整型变量才有效。
(ptNum是指向整数的指针,*ptNum是这个整数miles)
注意:
使用下标:如果程序按应用和手边数据的自然存储空间结构使用数组
使用指针:当讲解有关字符串和数据结构的知识时
传递和使用数组地址
一维数组元素能够用两种方式访问:
数组元素 | 下表符号 | 指针符号 |
---|---|---|
元素0 | grade[0] | *grade |
元素1 | grade[1] | *(grade+1) |
元素2 | grade[2] | *(grade+2) |
…… | …… | …… |
注意:保存到数组名称中的地址不能够被赋值语句改变。
类似grade=&grade[2];的语句是无效的
二维数组指针:
指针符号1 | 指针符号2 | 下标符号 |
---|---|---|
*(*nums) | *nums[0] | nums[0][0] |
*(*nums+1) | *(nums[0]+1) | nums[0][1] |
*(*nums+2) | *(nums[0]+1) | nums[0][1] |
((nums+1)) | *nums[1] | nums[1][0] |
((nums+1)+1) | *(nums[1]+1) | nums[1][1] |
((nums+1)+2) | *(nums[1]+2) | nums[1][2] |
使用指针创建字符串
下面两个初始化是有效的:
char message1[81] = “this is a string”;
char *message2 = “this is a string”;
从保存的观点看,message1和message2的空间分配是不同的。
message1:一个指定的81个存储空间被保留并且前17个位置被初始化。能够保存不同的字符串,但是每个字符串将覆盖前面已保存的字符。
message2:如果以后给它进行赋值,最初的字符串依然留在内存中,新的内存位置会分配给新的字符串。
message2例子:
#include <stdio.h>
int main()
{
char *message2 = "this is a string";
printf("\nThe string is %s", message2);
printf("\nThe base address of this string is %p\n", message2);
message2 = "A new message";
printf("\nThe string is %s", message2);
printf("\nThe base address of this string is %p\n", message2);
return 0;
}
输出:
The string is this is a string
The base address of this string is 00420094
The string is A new message
The base address of this string is 00420038
指针数组
声明:char *seasons[4]
初始化:
seasons[0]=“Winter”;
seasons[1]=“Spring”;
seasons[2]=“Summer”;
seasons[3]=“Fall”;
或
char *seasons[4] = {“Winter”,
“Spring”,
“Summer”,
“Fall”};
例子:
#include <stdio.h>
int main()
{
int n;
char *seasons[4] = {"Winter",
"Spring",
"Summer",
"Fall"};
printf("\nEnter a month (use 1 for Jan., 2 for Feb.,etc.):");
scanf("%d", &n);
n = (n % 12) / 3;
printf("The month entered is a %s month.\n", seasons[n]);
return 0;
}
注意:
指针数组和数组指针的区别:
指针数组(是数组):数组中的每个元素都存放指针。
例:*p[4]
p[0]、p[1]、p[2]、p[3]里面存放的都是指针
数组的指针(是指针):存放数组的行指针。
例:(*p)[4](二维数组指针,其中4表示一行有4个元素)
*p是第0行的地址
*(p+1)是第1行的地址
结构
单一结构
例1
声明
struct
{
int month;
int day;
int year;
}birth, current;
给出了一个名称为birth和一个名称为current的结构的形式
或
struct Date
{
int month;
int day;
int year;
};
Date是结构类型名称,它创建了一个这种声明形式的新结构类型。
struct Date birth, current;
赋值:
birth.month = 12;
birth.day = 28;
birth.year = 1987;
或
struct Date birth = {12,28,1987};
例2
声明:
struct PayRecord
{
char name[20];
int idNum;
double regRate;
double otRate;
};
定义和初始化
struct PayRecord employee = {“H.Price”, 12387, 15.89, 25.5};
例3(把一个结构包含在另一个结构内)
strcut Date
{
int month;
int day;
int year;
};
struct
{
char name[20];
struct Date birth;
}person;
赋值:
person.birth.month = 12;
结构数组
一个列表能够作为一个多个结构的单一数组处理。
例:
struct PayRecord {int idnum; char name[20]; double rate;};
10个这样的结构的数组能够定义为:
struct PayRecord employee[10];
传递结构
传递结构的副本:
#include <stdio.h>
struct Employee /*声明一个全局结构类型*/
{
int idNum;
double payRate;
double hours;
};
double calcNet(struct Employee); /*函数原型*/
int main()
{
struct Employee emp = {6787, 8.93, 40.5};
double netPay;
netPay = calcNet(emp); /*传递emp中的数值的副本*/
printf("The net pay of employee &d is $%6.2f\n", emp.idNum, netPay);
return 0;
}
double calcNet(struct Empolyee temp) /*temp是具有结构Employee的数据类型*/
{
return(temp.payRate * temp.hours);
}
传递结构的地址:
#include <stdio.h>
struct Employee /*声明一个全局结构类型*/
{
int idNum;
double payRate;
double hours;5
};
double calcNet(struct Employee *); /*函数原型*/
int main()
{
struct Employee emp = {6787, 8.93, 40.5};
double netPay;
netPay = calcNet(&emp); /*传递一个地址*/
printf("The net pay of employee &d is $%6.2f\n", emp.idNum, netPay);
return 0;
}
double calcNet(struct Empolyee *pt) /*pt是一个指向一个Employee类型结构的指针*/
{
return(pt->payRate * pt->hours);
}
注意:传递副本和传递地址中,函数原型、调用函数、函数首部行的区别
(*pt).idNum能够用pt->idNum取代,指pt里的地址指向的结构中的idNum成员
(*pt).payRate能够用pt->payRate取代
(*pt).hours能够用pt->hours取代
自增自减:
++pt->hours hours成员先被访问,后自增1(->比++优先级高)
(pt++)->hours hours成员被访问后,pt中地址增1
(++pt)->hours pt中地址增1,再hours成员被访问
联合
是一种保留两个或多个变量在内存中相同区域的数据类型。
声明:
union
{
char key;
int num;
double price;
}val;
或
union DateTime
{
long days;
double time;
};
union DateTime first, second, *pt;
联合可以是结构和数组的成员,结构、数组和指针可以是联合的成员。
struct
{
char uType;
union
{
char *text;
double rate;
}uTax;
}flag;
变量rate被引用为:flag.uTax.rate
地址保存到指针text中的字符串的第一个字符的访问方式是:*flag.uTax.text
结构和联合的区别:
1、在同一时刻,结构体的每个成员都有值,但是联合体在同一时刻只有一个成员有值。
2、当结构体变量的其中一个成员进行修改时,对其他成员没有影响;但修改联合体时,会将原来的成员值覆盖。
动态数据结构
链表
(用结构)
struct TeleType
{
char name[30];
char phoneNum[15];
struct TeleType *nextaddr;
};
最后一个成员是一个指针,适合于保存一个TeleType类型结构的地址。
#include <stdio.h>
#define MAXNAME 30
#define NAXPHONE 15
struct TeleType
{
char name[30];
char phoneNum[15];
struct TeleType *nextaddr;
};
int main()
{
struct TeleType t1 = {"Acme, Sam", "(555) 898-2392"};
struct TeleType t2 = {"Dolan, Edith", "(555) 682-3104"};
struct TeleType t3 = {"Lanfrank, John", "(555) 718-4581"};
struct TeleType *first;
void display(struct TeleType *);
first = &t1;
t1.nextaddr = &t2;
t2.nextaddr = &t3;
t3.nextaddr = NULL;
display(first);
return 0;
}
void display(struct TeleType *contents)
{
while(contents != NULL)
{
printf("%-30s %-20s\n", contents->name, contents->phoneNum);
contents = contents->nextaddr;
}
}
动态内存分配
函数:(头文件stdlib.h)
malloc()、calloc()、realloc()、free()
例:
malloc(10 * sizeof(char))请求足够的内存保存10个字符
malloc(sizeof(int))请求足够的内存保存一个整型数
grades = malloc(sizeof(int)); /变量grades是一个指向整型的指针/
(int *)grades; /定义grades为一个整型的地址/
#include <stdio.h>
#include <stdlib.h>
int main()
{
int numgrades, i;
int *grades;
printf(\nEnter the number of grades to be processed: ");
scanf("%d", &numgrades);
/*这里是进行请求存储区的地方*/
grades = (int *)malloc(numgrades * sizeof(int));
/*在这里我们检查这个分配是否被满足*/
if (grades == (int *) NULL)
{
printf("\nFailed to allocate grades array\n");
exit(1);
}
for (i=0; i<numgrades; i++)
{
printf("Enter a grade: ");
scanf("%d", &grades[i]);
}
printf("\nAn array was created for %d integers", numgrades);
printf("\nThe values stored in the array are: \n");
for (i=0; i<numgrades; i++)
printf("%d\n",grades[i]);
free(grades); /*存储区不需要时,把分配的存储块归还给堆是良好的习惯*/
return 0;
}
为结构动态地分配内存:
struct OfficeInfo
{
任意数量的数据成员在此声明;
};
struct OfficeInfo *off; /*创建一个指针存储这个被分配的地址*/
/*为一个结构空间请求空间*/
off = (struct OfficeInfo *)malloc(sizeof(struct OfficeInfo));
/*检查空间是否被分配*/
if (off == (struct OfficeInfo *) NULL)
{
printf("\nAllocation of office info structure failed\n");
exit(1);
}