c语言 指针问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c语言 指针问题相关的知识,希望对你有一定的参考价值。
指针的声明与初始化1、不恰当的指针声明
考虑如下的声明:
int* ptr1, ptr2; // ptr1为指针,ptr2为整数
正确的写法如下:
int* ptr1, *ptr2;
用类型定义代替宏定义是一个好的习惯,类型定义允许编译器检查作用域规则,而宏定义不一定会。
使用宏定义辅助声明变量,如下所示:
#define PINT int*
PINT ptr1, ptr2;
不过结果和前面所说的一致,更好的方法是使用下面的类型定义:
typedef int* PINT;
PINT ptr1, ptr2;
2、使用指针未初始化
在使用指针之前未初始化会导致运行时错误,如下面的代码:
int* p;
...
printf("%d\n", *p);
指针p未被初始化,可能含有垃圾数据
3、处理未初始化指针
总是用NULL来初始化指针
用assert函数
用第三方工具
把指针初始化为NULL更容易检查是否使用正确,即便这样,检查空值也比较麻烦,如下所示:
int *pi = NULL;
...
if(pi == NULL)
//不应该解引pi
else
//可以使用pi
我们可以使用assert函数来测试指针是否为空值:
assert(pi != NULL);
指针的使用问题
缓冲区溢出
缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量,使得溢出的数据覆盖在合法数据上,理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符,但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹配,这就为缓冲区溢出埋下隐患。操作系统所使用的缓冲区又被称为”堆栈”.。在各个操作进程之间,指令会被临时储存在”堆栈”当中,”堆栈”也会出现缓冲区溢出。
下面几种情况可能导致缓冲区的溢出:
访问数组元素时没有检查索引值
对数组指针做指针算术运算时不够小心
用gets这样的函数从标准输入读取字符串
误用strcpy和strcat这样的函数
1、测试NULL
使用malloc这样的函数的时候一定要检查返回值,否则可能会导致程序的非正常终止,下面是一般的方法:
float *vector = malloc(20 * sizeof(float));
if(vector == NULL)
//malloc分配内存失败
else
//处理vector
2、错误使用解引操作
声明和初始化指针的常用方法如下:
int num;
int *pi = #
下面是一种看似等价但是错误的声明方法:
int num;
int *pi;
*pi = #
3、迷途指针
参见《C迷途指针》
4、越过数组边界访问内存
没有什么可以阻止程序访问为数组分配的空间以外的内存,下面的例子中,我们声明并初始化了三个数组来说明这种行为:
#include<stdio.h>
int main()
char firstName[8] = "1234567";
char middleName[8] = "1234567";
char lastName[8] = "1234567";
middleName[-2] = 'X';
middleName[0] = 'X';
middleName[10] = 'X';
printf("%p %s\n", firstName, firstName);
printf("%p %s\n", middleName, middleName);
printf("%p %s\n", lastName, lastName);
return 0;
参考技术A B是错误的,D是正确的
D:*p1 *p2 都是指针所指向的内容,char类型属于整型,可以直接进行*运算。
B:错误 因为 P2是指针常量 C是字符常量 两者数据类型不一样。本回答被提问者和网友采纳 参考技术B 指针类型一般是4字节,字符型是1字节。
精度高的数据能赋值给精度低的类型变量,而反过来不行。这就是AD可以而B不可以的原因。 参考技术C p2是指针,c是字符,类型不同不能隐性转换
C语言 关于POINTER(指针)的问题, 急!!!!
谁能帮我详细地讲解一下什么是POINTER?作用是什么?在程序当中应该怎么用?
还有它与array、structure的关系,然后是怎么用的。
谢谢啦!,答的好有加分哦。。。
最难以学习的, 事实上 pointer 并不困难.
第一个范例:
/* ====================
pointer - 1
==================== */
#include <stdio.h>
int main()
char *s_pointer = “Hello”;
char s[] = “World”;
printf(“%s\n”, s_pointer );
printf(“%s”, s );
return 0;
程式执行结果:
Hello
World
先解释一下这一行:
char *s_pointer = “Hello”;
首先编译器会预留一块记忆空间存放 Hello, 再把这个空间的 address (也就是 ‘H’
字元的位址) 设定给 s_pointer.
有点困惑吗? C 的 pointer 与 array 很类似, 基本上 array 只是一块连续的记忆空间,
一个变数存放著这个空间的 address (位址), 而 pointer 也只是一个变数存放著一个
address. 若还是不明白, 在以后我们会以更多的范例来说明 pointer 的观念与使用
以及 pointer 与 array 的关系.
底下的例子:
/* ====================
pointer - 2
==================== */
#include <stdio.h>
int main()
char *s_pointer;
char str[] = “Hello World!”;
s_pointer = str;
printf(“%s\n”, s_pointer );
return 0;
执行结果:
Hello World!
上面程式中, 所做的事情不是 string copy, 而是将 pointer 所指的 address 设定(assign)
为 str 所指的值, 而此时有 str 及 pointer 指向 “Hello World!”.
再看底下的例子:
/* ====================
pointer - 3
==================== */
#include <stdio.h>
int main()
char *s_pointer;
char str[] = “Hello World!”;
s_pointer = str;
s_pointer[0] = ‘h’; /* ‘H’ 转 ‘h’ */
printf(“%s\n”, str );
return 0;
执行结果:
hello World!
前面提过, pointer 与 array 其实只是一个变数存放著一个 address, 在前面的 array 章节中
学到的 array 操作自然可以应用(apply)在 pointer 上, 我们把 s_pointer 所指的
address (位址) 上的第一个 element 改成 ‘h’. 又因为 str 所指的 address 与 s_pointer 一样,
所以 printf 输出 str 为 “hello World!”.
底下的例子:
/* ====================
pointer - 4
==================== */
#include <stdio.h>
int main()
char *s_pointer;
char str[] = “Hello World!”;
s_pointer = str;
s_pointer = s_pointer + 1; /* 也可写成 s_pointer++ */
printf(“%s\n”, str );
printf(“%s\n”, s_pointer );
return 0;
执行结果:
Hello World!
ello World!
既然我们可以指定 pointer 的 address (位址), 自然就可以将现在所指的 address
往前或往后减少或累加, 上例中我们是累加:
s_pointer = s_pointer + 1;
这一行程式会将 s_pointer 所指的 address 加一, 因此原本 s_pointer 是指向 ‘H’,
加一之后变成 ‘e’ 开始.
请参考下图.
str(指向 H )
H
e
l
l
o
W
o
r
l
d
!
NULL
s_pointer (指向 H)
s_pointer = s_pointer + 1 (指向 e)
/* ====================
pointer - 5
==================== */
#include <stdio.h>
int main()
char *s_pointer = “Hello”;
char ch1, ch2;
ch1 = *s_pointer;
ch2 = s_pointer[0];
printf(“%c, %c”, ch1, ch2 );
return 0;
执行结果:
H, H
程式示范如何以 pointer 运算取出目前 pointer 所指的 address 上的资料,
我们已知 s_pointer 所指的位址及其上面存放的资料, 以 ‘*’ pointer operator
(指标运算元) 可取出所存放的资料, 程式之中比较了等¤的 array 操作,
在程式开发上, 个人是偏爱使用 array operator, 但有些 programmer 认为
使用 pointer operator 编译器产生的 code 较 array operator 快.
以下范例是用 pointer 的间接运算子的例子, 当然也可以用 array operator 做到:
/* ====================
pointer 6
==================== */
#include <stdio.h>
void main()
char *str = "Eric";
printf( "%c", *(str+0) ); /* 也可写 printf(“%c”,str[0] ); */
printf( "%c", *(str+1) ); /* 也可写 printf(“%c”,str[1] ); */
printf( "%c", *(str+2) ); /* 也可写 printf(“%c”,str[2] ); */
printf( "%c", *(str+3) ); /* 也可写 printf(“%c”,str[3] ); */
程式执行结果:
Eric
看完以上的例子是否更清楚 pointer 的使用, 及 pointer 与 array 之间的关系?
在一个比较大的软体开发计划中, 常常 要动态向系统要求记忆体, 以下是一个范例:
/* ================
memory allocation/free 1
================ */
#include <stdio.h>
#include <stdlib.h>
int main()
char *str;
char s[] = “Hello World!”;
int length;
length = strlen( s ) + 1; /* 求得 s 长度, 加 1 是因为结束字元. */
str = (char*)malloc( length ); /* 向O.S 要 memory */
strcpy( str, s );
printf(“%s\n”, str );
str[0] = ‘h’;
printf(“%s\n”, s );
free( str );
return 0;
程式执行结果:
Hello World!
Hello World!
strlen 是 C 的 standard library 中求得 string length 的一个 function, 取得 s 的长度之后
加 1 是因为 strlen 并不会把结束字元算进字串的长度. 另外程式中,
以 malloc 这个函数向系统索取一块记忆空间, malloc 传回这个空间的 address.
str = (char *)malloc( length );
其中, (char *)是我们强制转型, 将 malloc传回的 pointer 型态转型与 str 一致为
(char *). 接著再以 strcpy 将 s 里面的字元 copy 至 str.
程式后面的 str[0] = ‘h’ 只是为了证明 str 与 s 所指的 address 及资料是完全不同的.
程式中以 free 这个 function 释放(release) 之前向系统索取的空间, 所谓有借有还,
维持良好的程式开发习惯.
/* ================
memory allocation/free 2
================ */
#include <stdio.h>
#include <stdlib.h>
int main()
char *str;
char s[] = “Hello World!”;
int length;
length = strlen( s ) + 1;
str = (char*)malloc( length ); /* 向O.S 要 memory */
if( str == NULL )
printf(“Memory allocation failed”);
return 0;
strcpy( str, s );
printf(“%s”,str );
free( str );
return 0;
执行结果, 记忆空间充足的情况”
Hello World!
或记忆空间不足时:
Memory allocation failed
上面的程式中, 我们多了一个判断, 判断 str 是否为 NULL, 若为 NULL 则印出
”Memory allocation Failed”, 接著离开程式返回系统, 因为 malloc 在无法取得
你所 大小的记忆空间时会传回 NULL. 这一个判断是必 的, 特别是在开发
大型系统时要处理这些问题.
最后谈到的是 & 位址运算元, 这个运算元符号虽然与 Bitwise AND 一样,
但用法不同, Bitwise AND 的用法是:
Identifier1 & Identifier2
而现在说的位址运算元是:
&Identifier
本运算元会传回 Identifier 的 Address(位址), 在 C 中, 所有的 variable (变数)
都存在一个实体的记忆体空间中, 当你 要知道这个变数存放的位址时,
就可以使用 “&” operator.
/* ====================
& operator.
==================== */
#include <stdio.h>
int main()
int *pointer_a, a;
pointer_a = &a;
a = 10;
printf(“%d, %d”, a, *pointer_a );
return 0;
执行结果:
10, 10
程式中, 将 a 的 address 设给 pointer_a (另一说法是: 把 pointer_a 这个 pointer 指向 a ),
因此 pointer_a 所”指”的 address 与 a 的 address 一样, 所以 a, 与使用 *pointer_a 取出
指向的位址上的资料是一样的.
在前面的”C的输出与输入”章节中, 函数 scanf 的参数皆是 pointer, 所以我们以
“&” operator 将变数的 address 传入.
参考资料:http://student.zjzk.cn/course_ware/gaojiyuyan/ckzl2/webver/ch27.htm
参考技术A 你用什么书学习C语言的不可能不讲指针,好好看书吧,C语言的精华和糟粕都在于指针 参考技术B http://student.zjzk.cn/course_ware/gaojiyuyan/ckzl2/webver/ch27.htm
建议去看看里面的例子!本回答被提问者采纳 参考技术C 汗
我也正在学习中
指针就是地址,作用是指向一个变量的地址 参考技术D 这个找本书看看吧
指针是一个指向地址的变量
以上是关于c语言 指针问题的主要内容,如果未能解决你的问题,请参考以下文章