C语言练习题笔记

本文介绍了C语言中指针与数组的关系,包括指针不能赋值为浮点数,数组下标的交换性质,以及数组作为函数参数时的注意事项。此外,还详细讨论了如何在不同约束条件下检测链表循环的方法,从简单的标记法到应对内存限制和链表长度不确定的复杂情况。最后,文章展示了指针在打印字符串时的用法,并列举了C语言中常用的格式化输出控制符。
摘要由CSDN通过智能技术生成

1、指针不能用浮点数之类常量赋值

char *p = “abcdefg”; //对字符串常量:在定义时同时赋给指针一个字符串常量进行初始化,会分配指针空间

float *pip = 3.14; / *错误无法通过编译,不能指望为浮点数之类的常量分配空间 * /

2、数组的形式 i[a] 和 a[i] 的关系是一样的

#include <stdio.h>

int main()
{
   /* 我的第一个 C 程序 */
   printf("Hello, World! \n");
	int a[6];
	for(int i = 0; i < 6; i++)
	{
		i[a] = i;
		printf("%d ",i[a]);
	}
	int b = 2[a];
	printf("\n%d",b);
   
   return 0;
}

image-20210504215219520

正确通过编译,在表达上中,指针和数组是可以互换的,因为他们在编译器里的最终形式都是指针,并且可以取下标操作。就像加法一样,取下标操作符的操作数都是可以交换的(它们不在意操作数的先后顺序,就像在加法中3+5和5+3并没有什么不一样)。这就是为什么在一个a[10]的声明中下面两种形式都是正确的:

a[6] = …;

6[a] = …;

3、数组实参的有效操作

#include <stdio.h>

int array[100], array2[100];

int main()
{
	printf("测试程序\n");
	array[1] = 3;
	*array = 3;
	array = array2;
	printf("%d , %d",array[1],*array);
  
   return 0;
}

image-20210505103050750

错误信息:

main.c: In function ‘main’:
main.c:10:8: error: assignment to expression with array type
10 | array = array2;
| ^

解释:上述语句array = array2;将引起一个编译时错误,错误信息是“无法修改数组名”。但是,arr = array2 却是合法的,因为arr虽然声明为一个数组但实际上却是一个指针。

#include <stdio.h>

int array[100], array2[100];

void fun1(int *ptr)
{
	ptr[1] = 3;
	*ptr = 3;
	printf("%d , %d\n",ptr[1],*ptr);
	ptr = array2;
	printf("%d , %d",ptr[1],*ptr);
}

int main()
{
	printf("测试程序\n");
	fun1(&array[0]);
  
   return 0;
}

image-20210505102522076

#include <stdio.h>

int array[100], array2[100];

void fun1(int ptr[])
{
	ptr[1] = 3;
	*ptr = 3;
	printf("%d , %d\n",ptr[1],*ptr);
	ptr = array2;
	printf("%d , %d",ptr[1],*ptr);
}

int main()
{
	printf("测试程序\n");
	fun1(&array[0]);
  
   return 0;
}

image-20210505102619366

4、怎样才能检测到链表中存在循环

这个问题看上去比较简单,“怎样才能检测到链表中存在循环?”但提问者不断对问题施加一些额外的限制,使这个问题很快就变得面目狰狞。
通常第一种答案:
对访问过的每个元素作个标记,继续遍历这个链表,如果遇到某个已经做过标记的元素,说明链表存在循环。
第二个限制:
这个链表位于只读内存区域,无法在元素上作标记。

通常第二种答案:
当访问每个元素时,把它存储在一个数组中。检查每一个后继的元素,看看它是否已经存在于数组中。有时候,一些可怜的程序员会纠缠于如何用散列表来优化数组访问的细节之中,结果在这一关卡了壳。
第三个限制:
噢!内存空间非常有限,无法创建一个足够长度的数组。然而,可以假定如果链表中存在循环,它出现在前N个元素之中。
**通常第三种答案(**如果这位程序员能够到达这一步):
设置一个指针,指向链表的头部。在接下去对直到第N个元素的访问中,把N-1个元素依次同指针指间的元素进行比较。然后指针移向第二个元素,把它与后面 N-2 个元素进行比较。根据这个方法依次进行比较,如果出现比较相等的情况就说明前 N个元素中存在循环,否则如果所有N个元素两两之间进行比较都不相等,说明链表中不存在循环。

第四个限制: 噢!不!链表的长度是任意的,而且循环可能出现在任何位置。(即使是优秀的候选者也会在这十关碰壁)
最后的答案:
首先,排除一种特殊的情况,就是3个元素的链表中第2个元素的后面是第1个元素。设置两个指针 pl和 p2,pl指向第个元素。p2指向第三个元素,看看它们是否相等。如果相等就属于上述这种特殊情况。如果不等,把pl向后移一个元素,p2向后移两个元素。检查两个指针的值,如果相等,说明链表中存在循环。如果不相等,继续按照前述方法进行。如果出现两个指针都是NULL的情况,说明链表中不存在循环。如果链表中存在循环,用这种方法肯定能够检测出来,因为其中一个指针肯定能够追上另一个(两个指针具有相同的值),尽管有可能要对这个链表经过几次便力才能检测出来。

这个问题还有其他一些答案,但是上面所说的几个是最常见的。

5、在关系表达式中负数和无符号整数比较时自动升级为正数

例子:
image-20210510173615963

结论:

因为sizeof返回的数是无符号整形

然后-1和无符号数比较后自动升级为无符号数了

然后就变成一个好大的数了

6、指针符号和多行注释冲突

image-20210510174147009

后果:

image-20210510174303844

7、指针打印字符串

#include <stdio.h>

int main()
{
	char *receiveData = NULL;
	receiveData = "ABCDEFG";
	printf("%c \n",*receiveData);
	printf("%s \n",receiveData);	
	printf("%s \n",&(*receiveData));	
    printf("%x",&receiveData);
   return 0;
}

输出:

image-20210517195203499

解释:receiveData 保存的是字符串的首地址,类似于数组。

%x 是以十六进制形式打印

注意 %s 的用法,%s 的对象是地址

image-20210517182634586

总结:在c语言中存储一个字符串,一般有两种方法,一种是字符指针,一种是使用字符数组。比如:

const char *str = "hello"; 
const char str[] = "hello"; 

C语言百分号加字母%d%p%o%x%u%c%s%f%e%g代表作用

%d整型输出,%ld长整型输出,

%p指针变量地址,如果数处数据不够8位数,则左边补零

%o以八进制数形式输出整数,

%x以十六进制数形式输出整数,

%u以十进制数输出unsigned型数据(无符号数)。

%c用来输出一个字符,

%s用来输出一个字符串,

%f用来输出实数,以小数形式输出,

%e以指数形式输出实数,

%g根据大小自动选f格式或e格式,且不输出无意义的零。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值