代码编织梦想

指针变量(指针):能够存储地址的变量
地址运算符&:&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)

注意:
使用下标:如果程序按应用和手边数据的自然存储空间结构使用数组
使用指针:当讲解有关字符串和数据结构的知识时

传递和使用数组地址

一维数组元素能够用两种方式访问:

数组元素下表符号指针符号
元素0grade[0]*grade
元素1grade[1]*(grade+1)
元素2grade[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);
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/weixin_47135547/article/details/106278319

【C语言】英文文章出现次数最多的单词-爱代码爱编程

问题描述: 在当前目录中存在文件名为“case14.in”的文本文件,其内容为一篇英文文章(以EOF作为结束标志)。现要求读取该文本文件内容,统计文章中每个单词出现的次数,并输出出现次数最多的前5个单词及其出现次数(按出现次数由多到少的顺序输出,次数相同时按字典顺序输出,不足5个单词时,按顺序输出全部单词)。程序中注意如下细节: (1)空格、标点符号与回车

C语言使用宏来指定打印信息头部-爱代码爱编程

main.c #include <stdio.h> #include "log.h" extern void lib_fun(); int main() { DEBUG_LOG("ni hao\r\n"); DEBUG_ERR("hehe\r\n"); lib_fun(); return 0; } lib.c #defin

指针函数倒序输出数组-爱代码爱编程

建立两个函数,第一个用来颠倒数组,第二个用来输出数组。 代码如下: #include<iostream> using namespace std; //颠倒数组 int* reverse(int *list,int size) { int i,t; for(i=0;i<size/2;i++){ t

C语言结构体-爱代码爱编程

本文引用自:https://baijiahao.baidu.com/s?id=1605775898311633565&wfr=spider&for=pc 结构体是一个或多个变量的集合,这些变量可以是不同的类型,为了处理的方便而将这些变量组织在一个名字之下。比如我要统某个班的学生信息(包括姓名,学号,成绩),每个学生都需要至少3个变量,如若

#C语言#对找完美数的一点理解-爱代码爱编程

题目:找出200以内的所有完数,并输出其因子。有一个数的因子之和为该数本身,称其为完数。 理解写在程序的注释内,欢迎讨论! #include<stdio.h> //核心还是遍历,但是在遍历的时候怎么存下来完数和它的因子是个难点 //完美数的定义:所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身 int main()

每天学习多少个小时的C语言,大概多久能完全掌握?-爱代码爱编程

从事软件行业十几年,中间经历过很多C语言的项目,想要掌握一门编程语言只是拿出多少时间来学习是不够的,主要还是要项目实战,没有参与真正的实战不要轻易说出掌握了什么编程语言,编程属于一种技术积累性的工作,理论很重要,实践更加重要。   任何一种编程语言的学习在具备理论的基础上,然后用项目实战来巩固理论知识,起码做上几个大项目才能真正说掌握一种编程语言。

【C语言】英文文章出现次数最多的单词-爱代码爱编程

问题描述: 在当前目录中存在文件名为“case14.in”的文本文件,其内容为一篇英文文章(以EOF作为结束标志)。现要求读取该文本文件内容,统计文章中每个单词出现的次数,并输出出现次数最多的前5个单词及其出现次数(按出现次数由多到少的顺序输出,次数相同时按字典顺序输出,不足5个单词时,按顺序输出全部单词)。程序中注意如下细节: (1)空格、标点符号与回车

c语言之形参和实参,全局变量和局部变量-爱代码爱编程

c语言中形参与实参: 形参 form parameter 实参 real parameter出现在函数定义中的参数,就叫形参出现在函数调用中的参数,就叫实参 函数定义: int max( int a , int b ) //这里的a,b就是形参 { //在函数中,形参就可以当作是一个局部变量。 if ( a>b ) return a; else

函数指针的使用举例-爱代码爱编程

定义类型 typedef void(*Fun)(void);   其中Fun就代表了“返回值为void,无参数的函数指针”型,举个例子: typedef void (*USER_EVENT_CB)(void); void _rh_conrol(void);//这个是要被调用的函数 void rh_handle(uint8_t mode ,USER

c语言之结构体-爱代码爱编程

结构体类型定义 格式: struct 类型标识符 { 类型名 成员名; 类型名 成员名; ... }; 例如: struct stu_type { char num[7]; //学号 char name[20]; //姓名 char sex; //性别 int age; //年龄 float score; //

C fopen vs open-爱代码爱编程

原问题:https://stackoverflow.com/questions/1658476/c-fopen-vs-open Is there any reason (other than syntactic ones) that you'd want to use FILE *fopen(const char *path, const char *

An Introduction To GCC-for the GNU Compilers gcc and g++(GCC 简介)-爱代码爱编程

Author: Brian Gough Foreword by Richard M. Stallman 文章目录 1. 简介2. 编译C程序2.1 例子:hello2.2 #include “FILE.h”和“#include < FILE.h>”2.3 从源文件生成对象文件2.4 从对象文件生成可执行文件2.5 对象文件的