C博客作业05-指针
| 这个作业属于哪个班级 | C语言--网络2011/2012 |
| ---- | ---- | ---- | ---- |
| 这个作业的地址 | C博客作业05--指针
| 这个作业的目标 | 学习指针相关内容 |
| 姓名 | 张官德 |
0. 展示PTA总分
1. 本章学习总结
1.1 指针定义、指针相关运算、指针做函数参数
1) 指针定义
- 指针是变量,如果在程序中声明一个变量并使用地址作为该变量的值,那么这个变量就是指针变量。但是指针的字节长度是固定的,因为指针保存的是地址,由操作系统的位数决定,32位机的字节是4,64位机的字节是8。
- 定义多个指针变量的时候,每一个指针变量前面都必须加上 *。
2)指针相关运算
- 取地址运算和间接访问运算
例如:
int *p,a=3;
p=&a;//间接访问
- 指针变量初始化
如:
int a;
int *p1=&a;//此处**\***只表示该变量是指针变量,它不是间接访问符
int *p2=p1;
- 指针自增(减)
int *p;
int a[10];
*p=&a;//p取数组首地址
p++;//表示p取数组下一个地址
3)指针做函数参数
- 如果将某个变量的地址作为函数的实参,相应的形参就是指针。
例如:
void Print(int *p);
int main(){
int *p;
int a=23;
p=&a;
Print(*p);
}
1.2 字符指针
- 如果定义一个字符指针接收字符串常量的值,该指针就是指向字符串的首字符。即字符指针。
例如:
char a[]="array";
char *p="point";
printf("%s",a);
printf("%s",p);
printf("%s\n","string");
printf("%s",a+2);
printf("%s",p+3);
printf("%s","string"+1);
//输出结果为:array point string
ray nt tring
1.3 指针做函数返回值
- C语言允许函数的返回值是一个指针(地址),我们将这样的函数称为指针函数。
例:
#include <stdio.h>
#define MAXS 30
char *search(char *s, char *t);
void ReadString( char s[] ); /* 裁判提供,细节不表 */
int main()
{
char s[MAXS], t[MAXS], *pos;
ReadString(s);
ReadString(t);
pos = search(s, t);
if ( pos != NULL )
printf("%d\n", pos - s);
else
printf("-1\n");
return 0;
}
/* 你的代码将被嵌在这里 */
1.4 动态内存分配
-
动态内存是相对静态内存而言的。所谓动态和静态就是指内存的分配方式。动态内存是指在堆上分配的内存,而静态内存是指在栈上分配的内存。
-
以前所写的程序大多数都是在栈上分配的,比如局部变量、形参、函数调用等。栈上分配的内存是由系统分配和释放的,空间有限,在复合语句或函数运行结束后就会被系统自动释放。而堆上分配的内存是由程序员通过编程自己手动分配和释放的,空间很大,存储自由。
动态内存分配相关做法
1) malloc函数
其函数原型为
void malloc(unsigned int size);
其作用是在内存的动态存储区中分配一个长度为size的连续空间。此函数的返回值是分配区域的起始地址,或者说,此函数是一个指针型函数,返回的指针指向该分配域的开头位置。如:
malloc(100);/开辟 100 个字节的临时分配域,返回值为其第一个字节的地址*/
注意指针的基类型为 void,即不指向任何类型的数据,只提供一个地址。如果此函数未能成功的执行(例如内存空间不足),则返回空指针(NULL)。
2)calloc函数
函数原型为
void calloc(unsigned n, unsigned size);
其作用是在内存的动态存储区中分配n个长度为 size 的连续空间。函数返回一个指向分配区域的起始位置的指针;如果分配不成功,则返回NULL。
采用 calloc 函数可以为一维数组开辟动态存储空间,n 为数组元素个数,每个元素长度为 size,这就是动态数组。如:
p = calloc(50,4) ,即 开辟 504个字节的临时分配域,把起始地址赋给指针变量p
俩者区别:
调用calloc函数时,自动初始化该内存空间为零,而调用malloc时则不初始化,里面的数据是随机的垃圾数据。
3) free函数
free 函数
函数原型为
void free(void*p);
其作用是释放指针 p 所指向的动态空间,使这部分空间能被其他变量使用。
1.5 指针数组及其应用
- 多个字符串用二维数组或指针数组表示
例如:
定义
int a[3][4];
其中,a 是二维数组名
a[0] 表示的就是元素 a[0][0] 的地址,即 a[0]&a[0][0];a[1] 表示的就是元素 a[1][0] 的地址,即 a[1]&a[1][0];
则a[0]+1 就表示元素 a[0][1] 的地址,a[0]+2 就表示元素 a[0][2] 的地址,a[1]+1 就表示元素 a[1][1] 的地址;
故a[i]+j == &a[i][j] &a[i][0]+j == &a[i][j] *(a+i)+j == &a[i][j]
1.6 二级指针
- A(即B的地址)是指向指针的指针,称为二级指针,用于存放二级指针的变量称为二级指针变量.根据B的不同情况,二级指针又分为指向指针变量的指针和指向数组的指针。
简单来说就是存储一级指针地址的地址。
1.7 行指针、列指针
定义:
在一个二维数组中每一行的首地址可以称为行指针,注意:第一行的首地址,是指首行一整行,并不是指某个具体元素。
如a[4][4]中a+0;a+1;a+2;等等都是“行指针”。
而第一个元素的地址,也就是a[0]+0。a[0]和a[0]+0都是指具体的元素。
对于这种,我们称之为“列指针”。
由上面的比较可以得出:
行指针:指向某一行,不指向具体的元素。
列指针:指向行中具体的元素
用途:
对于元素a[1][2],其地址用列指针表示为a[1]+2,等价表示为(a+1)+2,那么内容是(*(a+1)+2);
2.PTA实验作业
2.1藏尾诗
2.11 伪代码
char *poem[诗行数];
每一行诗的长度for(i=0;i<诗行数;i++){
len[i]=strlen(*(poem+i));
}
for (i = 0; i < 诗行数; i++) {
printf("%s", (*(str+i)+len[i]-2));\\指针指向那一行的倒数第三个位置(倒一是‘\')
}
2.22 代码截图
我的
同学的
我的特点就是遍历“诗”以指针锁定地址输出,他的则是重新定义一个p指针数组保存之前找到的地址再输出。
各有特点,但仍能学到许多。
2.2 合并两个有序数组
- 伪代码
void merge(int* a, int m, int* b, int n)
定义一个数组c分配内存c = (int*) malloc((m + n) * sizeof(int));
遍历数组for (i = j = k = 0;i<m并且j<n;) {
if (a中元素a[i]<b的元素b[j]) {
c[k++] = a[i++];//c储存小的那个数
}
else {
c[k++] = b[j++];
}
}
剩下的元素分配
if (m > n) {
while (i < m)
c[k++] = a[i++];
}
else {
while (j < n)
c[k++] = b[j++];
}
将c赋值给a
for (i = 0; i < k; i++) {
a[i] = c[i];
}
- 代码截图
我的
同学的
我的代码特点是比较简洁,但牺牲了运行速度。同学的以代码量换取了运行速度,值得借鉴。
2.3说反话-加强版
伪代码:
定义指针数组char* str1[250001];
分配内存
for (i = 0; i < 2000; i++) {
str1[i] = (char*)malloc( 250000* sizeof(char));//不建议,太耗内存了。。。
}
长度len=strlen(str)-1;//fgets输入的多一个‘\n’。
if (前一个是‘ ’后一个不是‘ ’) {
*(str + i + count) = '\0';//将每个单词“打包”
strcpy(str1[j], str + i);//赋值到二维数组中
j++;
count = 0;
}
if (i == 0 && *(str + i) != ' ') {
*(str + i + count) = '\0';
strcpy((str1[j]), str + i);
j++;
}//对首字母特殊处理
输出
代码截图:
与超星视频比较
我的做法是定义了一个指针数组用strcpy来储存每一个单词,这样子每一个字符数组都分配一样的内存,很耗内存,所以最后一个测试点没过。
看了超星视频以后,感觉没必要这么做了,它用printf("%.*s",长度len,地址p )就能直接将所需单词输出。
其他的思路差不多。
只能说get到了一个很有用的知识点。