【C语言】指针位运算
文章目录
- 一、前言
- 二、地址和指针的概念
- 三、变量的指针和指向变量的指针变量
- 3.1 定义一个指针变量
- 3.2 指针变量的引用
- 3.2.1 "&" 和"*"说明
- 3.3 指针变量作为函数参数
- 四、数组和指针
- 4.1 指向数组元素的指针
- 4.2 通过指针引用数组元素
- 4.3 输出数组中的全部元素
- 1、下标法
- 2、通过数组名计算数组元素地址,找出元素的值
- 3、 指针变量指向数组元素
- 4.4 用数组名作函数参数
- 4.4.1 将数组a中n个整数按相反顺序存放
- 4.4.2 用实参指针改写4.4.1
- 4.4.3 用选择法对10个整数按由大到小顺序排序
- 4.5 多维数组和指针
- 4.5.1 指向多维数组元素的指针变量
- 4.5.1.1 指向数组元素的指针变量
- 4.5.1.2 指向由m个元素组成的一维数组的指针变量
- 4.5.2 用指向数组的指针作函数参数
- 4.5.2.1 案例一
- 4.5.2.2 案例二
- 4.6 字符串和指针
- 4.1 用字符数组存放一个字符串,然后输出该字符串。
- 4.2 用字符指针指向一个字符串
- 4.2.1 定义字符指针
- 4.2.2 将字符串a赋值为字符串b
- 4.2.3 用指针变量来处理例4.2.2问题
- 4.2.4 字符指针作为函数参数
- 4.2.4.1 用字符数组作参数
- 4.2.4.2 形参用字符指针变量
- 4.2.5 使用字符指针变量和字符数组的讨论
- 4.2.5.1 改变指针变量的值
- 4.2.5.2 用带下标的字符指针变量引用字符串中的字符
- 五、指向函数的指针
- 5.1 函数指针变量调用函数
- 5.1.1 求a和b中的大者
- 5.2 指向函数的指针做函数参数
- 5.2.1 案例:函数process,在调用它的时候,每次实现不同的功能
- 5.3 返回指针值的函数:类型名 * 函数名(参数表列);
- 5.3.1 指针函数来实现案例
- 5.3.2 优化5.3.1
- 5.4 指针数组和指向指针的指针
- 5.4.1 指针数组案例
- 5.4.2 指向指针的指针案例
- 5.4.3 指针数组作main函数的形参
- 5.4.3.1
- 六、有关指针的数据类型和指针运算的小结
- 6.1 有关指针的数据类型的小结
- 6.2 指针运算小结
- 6.3 void指针类型
- 七、位运算
- 7.1 位运算符和位运算
- 7.1.1 按位与运算符“&”
- 7.1.2 按位或“|”
- 7.1.3 异或运算符:“^”
- 7.1.4 取反运算符“~”
- 7.1.5 左移运算符:“<<”
- 7.1.6 右移运算符:“>>”
- 7.1.7 位运算赋值运算符
- 7.1.8 不同长度的数据进行位运算
- 7.1.9 位段
一、前言
指针是C语言中的一个重要概念,也是C语言的一个重要特色。正确而灵活地运用它,可以有效地表示复杂的数据结构;能动态分配内存;方便地使用字符串;有效而方便地使用数组;在调用函数时能获得1个以上的结果;能直接处理内存单元地址等,这对设计系统软件是非常必要的。掌握指针的应用,可以使程序简洁、紧凑、高效。每一个学习和使用C语言的人,都应当深入地学习和掌握指针。可以说,不掌握指针就是没有掌握C的精华。
二、地址和指针的概念
变量的属性:名、值和地址
变量的访问方式:直接访问、间接访问
变量的地址称为该变量的“指针”
指针变量是存放地址的变量
#include
#define CHANGE 1int main(int argc, char *argv[]) {int i,j;int *i_pointer,*j_pointer; // 创建指针变量i_pointer = &i; // 变量的地址:该变量的指针j_pointer = &j;// printf("%d\n",sizeof(i_pointer));printf("i=%d\n",i); // 通过变量访问:直接访问 printf("i=%d\n",*i_pointer); // 通过指针变量访问:间接访问 *i_pointer = ireturn 0;
}
三、变量的指针和指向变量的指针变量
变量的指针就是变量的地址。存放变量地址的变量是指针变量,它用来指向另一个变量。为了表示指针变量和它所指向的变量之间的联系,在程序中用“*”符号表示“指向”。如果已定义i_pointer为指针变量,则(*i_pointer)是i_pointer所指向的变量。
#include int main(int argc, char *argv[]) {int i,j;int *i_pointer,*j_pointer; // 创建指针变量i = 12;i_pointer = &i; // 指向整型变量i,i_pointer存放的是变量i的地址j_pointer = &j;printf("i=%d\n",i); // 通过变量访问:直接访问 printf("*i_pointer=%d\n",*i_pointer); // 通过指针变量访问:间接访问 *i_pointer = ireturn 0;
}
3.1 定义一个指针变量
C语言规定所有变量在使用前必须定义,指定其类型,并按此分配内存单元。指针变量不同于整型变量和其他类型的变量,它是用来专门存放地址的,必须将它定义为“指针类型”。定义指针变量的一般形式为基类型 * 指针变量名;可以用赋值语句使一个指针变量得到另一个变量的地址,从而使它指向一个该变量。
(1)指针变量前面的“*”表示该变量的类型为指针型变量
(2)在定义指针变量时必须指定基类型
3.2 指针变量的引用
指针变量中只能存放地址(指针),不要将一个整数(或其他非地址类型的数据)赋给一个指针变量。有两个有关的运算符:(1)&:取地址运算符(2)*:指针运算符(或称“间接访问”运算符),取其指向的内容。
通过指针变量访问整型变量
#include int main(int argc, char *argv[]) {int a, b;int *pointer_1, *pointer_2; a = 100;b = 10;pointer_1 = &a;pointer_2 = &b;printf("%d, %d\n", a, b);printf("%d, %d\n", *pointer_1, *pointer_2);return 0;
}

3.2.1 “&” 和"*"说明

输入a和b两个整数,按先大后小的顺序输出a和b
#include int main(int argc, char *argv[]) {int *p1, *p2, a, b;scanf("%d,%d", &a, &b);p1 = &a;p2 = &b;if (a < b) {p1 = &b;p2 = &a;}printf("a=%d,b=%d\n", a, b);printf("max = %d,min = %d\n", *p1, *p2);return 0;
}

3.3 指针变量作为函数参数

1、输入a和b两个整数,按先大后小的顺序输出a和b
#include void swap(int *x, int *y) {// int *temp;// int i;// temp = &i;// *temp = *x; // i= a// *x= *y;// a= b// *y = *temp; // b= iint i;i = *x;*x = *y;*y = i;}int main(int argc, char *argv[]) {int a, b;scanf("%d,%d", &a, &b);if (a < b)swap(&a, &b);printf("max=%d min=%d\n", a, b);return 0;
}

2、输入a、b、c这3个整数,按大小顺序输出
#include void swap(int *x, int *y) {// int *temp;// int i;// temp = &i;// *temp = *x; // i= a// *x= *y;// a= b// *y = *temp; // b= iint i;i = *x;*x = *y;*y = i;
}void exchange(int *q1, int *q2, int *q3) {if (*q1 < *q2)swap(q1, q2);if (*q1 < *q3)swap(q1, q3);if (*q2 < *q3)swap(q2, q3);
}int main(int argc, char *argv[]) {int a, b, c;scanf("%d,%d,%d", &a, &b, &c);exchange(&a, &b, &c);printf("%d %d %d\n", a, b, c);return 0;}

四、数组和指针

4.1 指向数组元素的指针

#include int main(int argc, char *argv[]) {int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};int *p;p = a;p = &a[9];// a[9]指针地址复制给指针pprintf("*p = %d\n", *p);return 0;
}

4.2 通过指针引用数组元素

#include int main(int argc, char *argv[]) {int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};int *p;p = a;// p = &a[0];// a[9]指针地址复制给指针p*p = 1;printf("a[0]=%d\n", *p);return 0;
}


4.3 输出数组中的全部元素

1、下标法
#include int main(int argc, char *argv[]) {int a[10];for (int i = 0; i < 10; i++) {scanf("%d", &a[i]);}for (int i = 0; i < 10; i++) {printf("%d\n", a[i]); // 下标法}return 0;
}
2、通过数组名计算数组元素地址,找出元素的值
#include int main(int argc, char *argv[]) {int a[10];for (int i = 0; i < 10; i++) {scanf("%d", &a[i]);}for (int i = 0; i < 10; i++) {printf("%d", *(a + i)); // 下标法}return 0;
}
3、 指针变量指向数组元素
#include int main(int argc, char *argv[]) {int a[10];int *p;p = a;for (int i = 0; i < 10; i++) {scanf("%d", &a[i]);}for (int i = 0; i < 10; i++) {printf("%d", *(p + i)); // 下标法}return 0;
}
4、通过指针变量输出a数组的10个元素
#include int main(int argc, char *argv[]) {int a[10];int *p;p = a;for (int i = 0; i < 10; i++) {scanf("%d", &a[i]);}for (int i = 0; i < 10; i++) {printf("%d", *(p + i)); // 下标法}return 0;
}
4.4 用数组名作函数参数
如果一个实参数组,要想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下4种情况
(1)形参和实参都用数组名
(2)实参用数组名,形参用指针变量
(3)实参形参都用指针变量
(4)实参为指针变量,形参为数组名
4.4.1 将数组a中n个整数按相反顺序存放
#include void inv(int x[], int n) {int i, j;for (i = 0, j = n - 1; i <= (n - 1) / 2; i++, j--) {int temp;temp = x[i]; // x[i]==*(x+i)x[i] = x[j]; // x[j]==*(x+j)x[j] = temp;}
}int main(int argc, char *argv[]) {int a[10];for (int i = 0; i <= 9; i++)scanf("%d", &a[i]);inv(a, 10);for (int i = 0; i <= 9; i++)printf("%d,", a[i]);return 0;
}

4.4.2 用实参指针改写4.4.1
#include void inv(int *x, int n) {int i, j;for (i = 0, j = n - 1; i <= (n - 1) / 2; i++, j--) {// int temp;// temp = x[i]; // x[i]==*(x+i)// x[i] = x[j]; // x[j]==*(x+j)// x[j] = temp;int temp;temp = *(x + i);*(x + i) = *(x + j);*(x + j) = temp;}
}int main(int argc, char *argv[]) {int a[10];for (int i = 0; i <= 9; i++)scanf("%d", &a[i]);int *p;p = a; // 指向数组首地址// p = &a[0];inv(p, 10);for (int i = 0; i <= 9; i++)printf("%d,", a[i]);return 0;
}
4.4.3 用选择法对10个整数按由大到小顺序排序
#include void sort(int x[], int n) {for (int i = 0; i < n - 1; i++) {int p = i;for (int j = i + 1; j < n; j++)if (x[j] < x[p])p = j;// 更新指针if (p != i) {int temp;temp = x[p];x[p] = x[i];x[i] = temp;}}
}int main(int argc, char *argv[]) {int a[10];int *p = a;for (int i = 0; i < 10; i++)scanf("%d", p++);p = a; // 初始化首地址sort(p, 10);for (int i = 0; i < 10; i++)printf("%d ", *(p + i));return 0;
}

4.5 多维数组和指针


输出二维数组有关的值
#include int main(int argc, char *argv[])
{int a[3][4] = {{1, 3, 5, 7}, {9, 11, 13, 15}, {17, 19, 21, 23}};printf("%x,%x\n", a, *a); //*a==a[0]printf("%x,%x\n", a[0], *(a + 0)); //*(a+0)==a[0]printf("%x,%x\n", &a[0], &a[0][0]); //&a[0]==a+0printf("%x,%x\n", a[1], a + 1);printf("%x,%x\n", &a[1][0], *(a + 1) + 0); //*(a+1)==a[1]printf("%x,%x\n", a[2], *(a + 2)); //*(a+2)==a[2]printf("%x,%x\n", &a[2], a + 2);printf("%d,%d\n", a[1][0], *(*(a + 1) + 0));// a+1:第一行 + 0:第一行第0个元素return 0;
}

4.5.1 指向多维数组元素的指针变量
4.5.1.1 指向数组元素的指针变量
用指针变量输出二维数组元素的值
#include int main(int argc, char *argv[])
{int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};int *p; // 创建指针pfor (p = a[0]; p < a[0] + 11; p++){if ((p - a[0]) % 4 == 0) // 每四个元素换行printf("\n");printf("%d ", *p);}printf("\n");return 0;
}

4.5.1.2 指向由m个元素组成的一维数组的指针变量
输出二维数组任一行任一列的值
#include int main(int argc, char *argv[])
{int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};int (*p)[4]; // p是一个指针变量,指向大小为4的一维数组p = a;// 指向二维数组的第一行的一维数组int i,j;scanf("%d %d",&i,&j);printf("%d\n", *(*(p+i)+j)); // p+i行, +j,第j列return 0;
}

4.5.2 用指向数组的指针作函数参数
一维数组名可以作为函数参数传递,多维数组名也可作函数参数传递。在用指针变量作形参以接受实参数组名传递来的地址时,有两种方法:
1、用指向变量的指针变量
2、用指向一维数组的指针变量
4.5.2.1 案例一
有一个班,3个学生,各学4门课,计算总平均分数以及第n个学生的成绩
#include float average(float *p, int n)
{float *start;float sum = 0.0;for (start = p; p <= start + n - 1; p++){ // 将指针p赋给start指针,start+n-1:一共的元素sum += *p; // 统计分数和}return sum / n; // 返回平均分
}void search(float (*p)[4], int n)
{ // p是一个指针变量,指向大小为4的一维数组for (int i = 0; i < 4; i++){printf("%f ", *(*(p + n) + i)); // p+n 第n行 +i 第i列}printf("\n");
}int main(int argc, char *argv[])
{float score[3][4] = {{65, 67, 70, 60}, {80, 87, 90, 81}, {90, 99, 100, 98}};printf("average=%f\n", average(*score, 12)); //*score==score[0]search(score, 2); // 行标是2的人的分数return 0;
}

4.5.2.2 案例二
在上题基础上,查找有一门以上课程不及格的学生,输出他们的全部课程的成绩
#include void search(float (*p)[4], int n) { // p是一个指针变量,指向大小为4的一维数组for (int i = 0; i < n; i++) {int flag = 0;for (int j = 0; j < 4; j++) {if (*(*(p + i) + j) < 60.0) {flag = 1;break;}}// 打印if (flag == 1) {printf("%d:\n",i);for (int j = 0; j < 4; j++) {printf("%f ", *(*(p + i) + j)); // 第几行第几列}printf("\n");}}
}int main(int argc, char *argv[]) {float score[3][4] = {{55, 67, 70, 60}, {50, 87, 90, 81}, {90, 99, 100, 98}};search(score, 3); // 行标是2的人的分数return 0;
}

4.6 字符串和指针
在C程序中,可以用两种方法访问一个字符串
4.1 用字符数组存放一个字符串,然后输出该字符串。
1、定义一个字符数组,对它初始化,然后输出该字符串
#include int main(int argc, char *argv[])
{char string[] = "I love China!"; // !后面会自动加一个\0printf("%s\n", string);//string++;return 0;
}
4.2 用字符指针指向一个字符串
4.2.1 定义字符指针
#include int main(int argc, char *argv[])
{// char string[] = "I love China!"; // !后面会自动加一个\0char *string = "I love China!";printf("%s\n", string);return 0;
}
4.2.2 将字符串a赋值为字符串b
#include int main(int argc, char *argv[])
{int i;char a[] = "I am a boy.", b[20];for (i = 0; *(a + i) != '\0'; i++){*(b + i) = *(a + i);}*(b + i) = '\0'; // 字符串结束标识for (i = 0; b[i] != '\0'; i++)printf("%c", b[i]);printf("\n");printf("%s\n", b);return 0;
}

4.2.3 用指针变量来处理例4.2.2问题
#include int main(int argc, char *argv[])
{int i;char a[] = "I am a boy.", b[20];char *p, *q;for (p = a, q = b; *p != '\0'; p++, q++) // p,q分别指向数组a[]和b[]第一个元素{*q = *p;}*q = '\0';q = b; // 重新初始化printf("%s\n", q);return 0;
}

4.2.4 字符指针作为函数参数
将一个字符串从一个函数传递到另一个函数,可以用地址传递的方法,即用字符数组名作参数,也可以用指向字符的指针变量作参数。在被调用的函数中可以改变字符串的内容,在主调函数中可以得到改变了的字符串。
用函数调用实现字符串的复制
4.2.4.1 用字符数组作参数
#include void copy_string(char from[], char to[])
{int i = 0;while (from[i] != '\0'){to[i] = from[i];i++;}to[i] = '\0';
}int main(int argc, char *argv[])
{char a[] = "I am a teacher.";char b[] = "You are student.";printf("string a=%s string b=%s\n", a, b);printf("copy string a to string b:\n");copy_string(a, b);printf("string a=%s string b=%s\n", a, b);return 0;
}

4.2.4.2 形参用字符指针变量
#include void copy_string(char *from, char *to)
{// 方式一// for (; *from != '\0'; from++,to++)// {// *to = *from;// }// *to = '\0';// 方式二// while(*from != '\0'){// *to = *from;// from++;// to++;// }// 方式三// while (*from != '\0')// {// *to++ = *from++;// }// *to = '\0';// 方式四while(*to++ = *from++);}int main(int argc, char *argv[])
{char a[] = "I am a teacher.";char b[] = "You are student.";printf("string a=%s string b=%s\n", a, b);printf("copy string a to string b:\n");char *from = a;char *to = b;copy_string(from, to);printf("string a=%s string b=%s\n", a, b);return 0;
}

4.2.5 使用字符指针变量和字符数组的讨论
虽然用字符数组和字符指针变量都能实现字符串的存储和运算,但它们两者之间是有区别的,不应混为一谈,主要有以下几点。
(1)字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址,决不是将字符串放到字符指针变量中。
(2)赋值方式。
(3)对字符指针变量赋初值。
(4)如果定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址。而定义一个字符指针变量时,给指针变量分配内存单元,在其中可以放一个字符变量的地址,也就是说,该指针变量可以指向一个字符型数据,但如果未对它赋予一个地址值,则它并未具体指向一个确定的字符数据。
(5)指针变量的值是可以改变的。
4.2.5.1 改变指针变量的值
int main(int argc, char *argv[])
{char *a = "I love China!";a = a + 7;// char a[] = "I love China!";// a = a + 7;printf("%s", a);return 0;
}
4.2.5.2 用带下标的字符指针变量引用字符串中的字符
用指针变量指向一个格式字符串,可以用它代替printf函数中的格式字符串。
int main(int argc, char *argv[])
{char *a = "I love China!";printf("The sixth character is %c\n", *(a + 5)); //a[5]==*(a+5)for (int i = 0; *(a + i) != '\0'; i++)printf("%c", a[i]);printf("\n");char *format = "a=%d,b=%d\n";int aa = 1, bb = 2;printf(format, aa, bb);return 0;
}

五、指向函数的指针
5.1 函数指针变量调用函数
可以用指针变量指向整型变量、字符串、数组,也可以指向一个函数。一个函数在编译时被分配给一个入口地址。这个函数的入口地址就称为函数的指针。可以用一个指针变量指向函数,然后通过该指针变量调用此函数。
5.1.1 求a和b中的大者
#include int max(int a, int b)
{if (a > b)return a;elsereturn b;
}int min(int a, int b)
{if (a > b)return b;elsereturn a;
}int main(int argc, char *argv[])
{int a, b;scanf("%d %d", &a, &b);printf("max=%d\n", max(a, b));int (*p)(int,int); // (*p):指针变量---指向函数的类型--->(int,int):函数形参类型p = max; // 指向函数首地址printf("max=%d\n", (*p)(a, b));return 0;
}

说明
(1)指向函数的指针变量的一般定义形式为:数据类型 (*指针变量名) (函数参数表列);
(2)函数的调用可以通过函数名调用,也可以通过函数指针调用(即用指向函数的指针表量调用)。
(3)“int (*p)(int,int);”表示定义一个指向函数的指针变量p,它不是固定指向哪一个函数的,而是表示定义了这样一个类型的变量,它是专门用来存放函数的入口地址的。
(4)在给函数指针变量赋值时,只需给出函数名而不必给出参数。
(5)用函数指针变量调用函数时,只需将(*p)代替函数名即可,在(*p)之后的括号中根据需要写上实参。
(6)对指向函数的指针变量,像p+n、p++等运算是无意义的。
5.2 指向函数的指针做函数参数
函数指针变量通常的用途之一是把指针作为参数传递到其他函数。函数的参数可以是变量、指向变量的指针变量、数组名、指向数组的指针变量等。函数的指针也可以作为参数,以实现函数地址的传递,这样就能够在被调用的函数中使用实参函数。
5.2.1 案例:函数process,在调用它的时候,每次实现不同的功能
设一个函数process,在调用它的时候,每次实现不同的功能。输入a和b两个数,第一调用process时找出a和b中大者,第二次找出其中小者,第三次求a与b之和
#include int max(int a, int b)
{if (a > b)return a;elsereturn b;
}int min(int a, int b)
{if (a > b)return b;elsereturn a;
}int add(int a, int b)
{return a + b;
}void process(int a, int b, int (*p)(int, int)) // 指向函数的指针做函数参数
{printf("%d\n", (*p)(a, b));
}int main(int argc, char *argv[])
{int a, b;scanf("%d %d", &a, &b);process(a, b, max);process(a, b, min);process(a, b, add);return 0;
}

5.3 返回指针值的函数:类型名 * 函数名(参数表列);
一个函数可以返回一个整型值、字符值、实型值等,也可以返回指针型的数据,即地址。其概念与以前类似,只是返回的值的类型是指针类型而已。
这种返回指针值的函数,一般定义形式为类型名 * 函数名(参数表列);
5.3.1 指针函数来实现案例
有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号后,能输出该学生的全部成绩。用指针函数来实现
#include int *search(int n, int (*p)[4]) // 一维数组指针类型
{return *(p + n); //*(p+n)==score[n]
}int main(int argc, char *argv[])
{int score[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};//score score[0] score[1] score[2]int *p = search(1, score);for (int i = 0; i < 4; i++)printf("%d ", *(p + i));return 0;
}

5.3.2 优化5.3.1
对上例中的学生,找出其中不及格课程的学生及其学生号
#include int *search(int (*p)[4])
{for (int i = 0; i < 4; i++){if (*(*p + i) < 60) // 当前一维数组*p + i第i个元素{return *(p + 1); // 指向下一个一维数组指针}}return *p; // 一维数组
}int main(int argc, char *argv[])
{int score[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};for (int i = 0; i < 3; i++){int *p = search(score + i);if (p != *(score + i)) // 行类型指针{printf("student number=%d\n", i);for (int j = 0; j < 4; j++)printf("%d ", *(*(score + i) + j));printf("\n");}}return 0;
}

5.4 指针数组和指向指针的指针
一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都相当于一个指针变量。一维指针数组的定义形式为
类型名 * 数组名[数组长度];例如:int * p[4];
5.4.1 指针数组案例
将若干字符串按字母顺序输出
#include
#include void sort(char *name[], int n) // 字符指针数组类型
{for (int i = 0; i < n - 1; i++) // 选择法,n个元素需要n-1次排序{int p = i;for (int j = i + 1; j < n; j++){if (strcmp(name[j], name[p]) < 0){p = j; // 改变指针的位置}}if (p != i){char *temp;temp = name[i];name[i] = name[p];name[p] = temp;}}
}void print(char *name[], int n)
{for (int i = 0; i < n; i++){printf("%s\n", name[i]);}
}int main(int argc, char *argv[])
{char *name[5] = {"Follow me", "BASIC", "Great Wall", "FORTRAN", "Computer design"};sort(name, 5);print(name, 5);return 0;}

5.4.2 指向指针的指针案例
1、使用指向指针的指针
#include int main(int argc, char *argv[])
{char *name[5] = {"Follow me", "BASIC", "Great Wall", "FORTRAN", "Computer design"}; // 字符指针的数组char **p; // 指向字符指针的指针// for (int i = 0; i < 5; i++)// {// p = name + i; // 字符指针的指针// printf("%s\n", *p); // 第i个元素// }p = name + 1;printf("%c\n",**p);printf("%c\n", *(*p+1)); // *p--->name[1]return 0;
}

2、指针数组的元素指向整型数据
#include int main(int argc, char *argv[])
{int a[5] = {1, 2, 3, 4, 5};int *num[5] = {&a[0], &a[1], &a[2], &a[3], &a[4]}; // 指针数组int **p; // 指向指针的指针p = num; // 指针数组的第一个元素for (int i = 0; i < 5; i++){printf("%d ", **p);p++;}return 0;
}

5.4.3 指针数组作main函数的形参
指针数组的一个重要应用是作为main函数的形参。在以往的程序中,main函数的第一行一般写成以下形式:void main()括号中是空的。实际上,main函数可以有参数,例如:void main(int argc, char * argv[])
5.4.3.1
#include int main(int argc, char *argv[]) // *argv[]:指针数组
{for (int i = 0; i < argc; i++){printf("%s\n", argv[i]);}getchar();return 0;
}

六、有关指针的数据类型和指针运算的小结
6.1 有关指针的数据类型的小结

6.2 指针运算小结
(1)指针变量加(减)一个整数
#include int main(int argc, char *argv[]) // *argv[]:指针数组
{int a[5] = {1, 2, 3, 4, 5};int *p;p = a;//printf("%x\n",*p);printf("%x\n", p);p++;printf("%x\n", p);return 0;}
(2)指针变量赋值
#include int main(int argc, char *argv[]) // *argv[]:指针数组
{int a[5] = {1, 2, 3, 4, 5};int *p;p = a;int i = 5;p = &i;printf("%d\n",*p);return 0;
}

(3)指针变量可以有空值,即该指针变量不指向任何变量
#include int main(int argc, char *argv[]) // *argv[]:指针数组
{int a[5] = {1, 2, 3, 4, 5};int *p;p = NULL;// if(p == NULL){// }else// {// /* code */// }printf("%x\n", p);return 0;
}
(4)两个指针变量可以相减
#include int main(int argc, char *argv[]) // *argv[]:指针数组
{int a[5] = {1, 2, 3, 4, 5};int *p1, *p2;p1 = &a[0];p2 = &a[1];printf("p2-p1 = %d\n", (p2-p1));return 0;
}
(5)两个指针变量比较
#include int main(int argc, char *argv[]) // *argv[]:指针数组
{int a[5] = {1, 2, 3, 4, 5};int *p1, *p2;p1 = &a[0];p2 = &a[4];printf("p2==p1 = %d\n", p2==p1);return 0;
}

6.3 void指针类型

#include
#include int main(int argc, char *argv[]) // *argv[]:指针数组
{char *string;string = NULL;string = (char *)malloc(5);if (string == NULL)printf("Insufficient memory available\n");else{*(string + 0) = 'a';*(string + 1) = 'b';*(string + 2) = 'c';*(string + 3) = 'd';*(string + 4) = '\0';printf("%s\n", string);free(string);printf("Memory freed\n");}return 0;
}

七、位运算

7.1 位运算符和位运算

7.1.1 按位与运算符“&”

7.1.2 按位或“|”

7.1.3 异或运算符:“^”


#include
#include // 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{int a = 3;int b = 4;a = a ^ b;b = b ^ a;a = a ^ b;printf("a=%d b=%d\n", a, b);return 0;
}

7.1.4 取反运算符“~”

int a = 122388;int c = ~a;printf("a=%d\n", c);
7.1.5 左移运算符:“<<”

#include
#include // 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{int a = 2;int c =a<<1;printf("a=%d\n", c);return 0;
}

7.1.6 右移运算符:“>>”

7.1.7 位运算赋值运算符

int a = 0x80000001;a = a>>1;a>>=1;
7.1.8 不同长度的数据进行位运算

7.1.9 位段
实际上,有时存储一个信息不必用一个或多个字节,例如,“真”或“假”用0或1表示,只需1位即可。在计算机用于过程控制、参数检测或数据通信领域时,控制信息往往只占一个字节中的一个或几个二进制位,常常在一个字节中放几个信息。
向一个字节中的一个或几个二进制位赋值和改变它的值,可以用以下两种方法:
(1)可以人为地将一个整型变量data分为几部分。
(2)段位结构体
C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这样以位为单位的成员称为“位段”或称“位域”。利用位段能够用较少的位数存储数据。例如:
struct packed_data{unsigned a:2;unsigned b:6;unsigned c:4;unsigned d:4;int i;} data;
#include
#include struct packed_data
{unsigned int a : 2; // 占用两个二进制位unsigned int b : 3;unsigned int c : 4;int i;}data;
// 主函数
int
main(int argc, char *argv[]) // *argv[]:指针数组
{data.a = 3;data.b = 7;data.c =15;data.i = 2345678;printf("%d %d %d %d\n", data.a, data.b, data.c, data.i);return 0;
}

说明

案例
1、编写一个函数getbits,从一个16位的单元中取出某几位(即该几位保留原值,其余位为0)。函数调用形式为getbits(value, n1, n2),value为该16位(2个字节)中的数据值,n1为欲取出的起始位,n2为欲取出的结束位,例如:getbits(0101675,5,8)表示对八进制101675这个数,取出它的从左面起第5位到第8位。
#include
#include unsigned short getbits(unsigned short int value, int n1, int n2)
{return (unsigned short int)(value << (n1 - 1)) >> (16 - (n2 - n1 + 1));//00000000 00000000 00000000 10000011
}// 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{unsigned short int a;printf("%x\n", getbits(0101675, 5, 8));return 0;
}

2、 编写一函数用来实现左右循环移位。函数名为move,调用方法为move(value, n),其中value为要循环位移的数,n为位移的位数。例如,n<0表示为左移;n>0为右移。n=4表示要右移4位;n=-3表示要左移3位。
#include
#include
unsigned int move(unsigned int value, int n)
{unsigned int t1, t2;if (n > 0){t1 = value << (32 - n);t2 = value >> n;}else{t1 = value >> (32 + n); // 负数t2 = value << (-n);}return t1 | t2;}// 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{unsigned int a;a = 0x12345678;printf("%x\n", a);printf("right>>%x\n", move(a, 4));printf("left<<%x\n", move(a, -4));return 0;
}

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
