压缩字符串与运用指针数组循环后移(典例)

本文介绍了如何使用C语言实现字符串的压缩,通过计数重复字符并以数字表示,同时还包括了数组元素的循环后移算法及水仙花数的判断程序。

压缩字符串

#include<stdio.h>
#define M 80
void zip(char *p);
int main()
{
	char line[M];
    gets(line);			//以回车结束,可以有空格。
    zip(line);
    puts(line);			//输出完字符串自动换行。
    return 0; 
}
void zip(char *p)
{
	char *q=p;				//定义一个新的指针来对调用的指针变量进行变化
	int n;
	while(*p!='\0')
	{
		n=1;						//对n进行重置
		while(*p==*(p+n))
		{
			n++;					//每一次遇见相同的字母只会有一个n
   	 }
   	 if(n>=10)
   	 {
   	 	*q++=(n/10)+'0';
   	 	*q++=(n%10)+'0';			//n大于10占两个字符位 
   	 }
   	 else if(n>=2)
   	 {
   	 	*q++=n+'0';					//让第一个重复字母为重复次数
   	 }
   	 *q++=*(p+n-1);			//重新复制字符
   	 p=p+n;				//跳过相同字符
    }
    *q='\0';						//出现新的结束标志
}

数组循环后移

#include<stdio.h>
#define M 100
void mov(int *x,int n,int m);
int main()
{
   int *p,a[M],m,n,i;
   scanf("%d %d",&m,&n);
   for(p=a,i=0;i<n;i++)
   {
   	scanf("%d",&*p++);	
   }
   mov(a,n,m);
   printf("After moved:");
   for(i=0;i<n;i++)
   {
   	printf("%5d",a[i]);
   	}
   	return 0;
   	}
   	void mov(int *x,int n,int m)
   	{
   		int i,j,temp;
   			m=m%n;				//简化循环次数
   			for(i=0;i<m;i++)			//循环几次
   			{
   				int c=x[n-1];			//中间变量保留啊x[n-1]
   				for(j=n-1;j>0;j--)
   				{
   					x[j]=x[j-1];			//从后往前移动一次
   					}
   						x[0]=c;
   						}
   	}

水仙花数之小结

int main()
   {
   	int n,sum=0,c=0,i,m,d,j,flag=3;
   	scanf("%d %d",&i,&m);
   	for( ;i<m;i++)
   	{
   		d=c=i;
   		sum=0;
   		for( j=0;c!=0;j++){
   			c/=10;
   		}
   		for(int k=0;k<=j;k++)
   		{
   			n=d%10;
   			sum=sum+pow(n,j);
   			d/=10;
   		}
   		if(flag!=j){
   			printf("\n");					//关键的换行步骤
   			flag=j;
   		}
   		if(i==sum&&j==3)
   		{
   		printf("水仙花数%-6d ",sum);
   		
   	    }
   	    if(i==sum&&j==4)
   		{
   			printf("玫瑰花数%-6d ",sum);
   		 } 
       }
   	return 0;
   }					
分数 1 作者 张泳 单位 浙大城市学院 数组的基地址是在内存中存储数组的起始位置,数组名本身就是一个地址即指针值。 T F 分数 1 作者 张泳 单位 浙大城市学院 对于定义int a[10],*p=a; 语句p=a+1;和a=a+1;都是合法的。 T F 分数 1 作者 张泳 单位 浙大城市学院 两个任意类型的指针可以使用关系运算符比较大小。 T F 分数 1 作者 张泳 单位 浙大城市学院 冒泡排序效率较高,因为它只需要约 1.jpg 次比较。 T F 分数 1 作者 陶煜波 单位 浙江大学 执行以下代码后,变量x的值为042,变量y的值为87,变量z的值为0x4e。 int a[10] = { '\012', 34, '\x56', 78, 0x910 }, *p = a + 1; int x = *p++; int y = ++*p; int z = *++p; T F 分数 1 作者 陶煜波 单位 浙江大学 变量定义如下,指针变量q的值比指针变量p的值大sizeof(char)。 int a[5]; int *p = a; char *q = (char *)p + 1; T F 分数 1 作者 陶煜波 单位 浙江大学 定义数组int a[10];,则表达式(int)(&a + 1) - (int)&a的值为4。 T F 分数 1 作者 陶煜波 单位 浙江大学 函数申明和使用代码如下,当调用该函数时,实参数组b的10个元素的值单向传递给形参数组a的10个元素。 int fun(int a[10]); int b[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; fun(b); T F 分数 1 作者 陶煜波 单位 浙江大学 形参为数组的函数在编译后都转化为形参为指针的函数,如int fun(int a[10])转化为int fun(int *a)。 T F 分数 1 作者 陶煜波 单位 浙江大学 字符串压缩代码如下,char *q = p;是将指针变量p的值(字符串首字符的地址)赋值给指针变量*q。 void zip(char *p) { char *q = p; ...... } T F 分数 1 作者 张泳 单位 浙大城市学院 字符串常量在内存中的存放位置由系统自动安排。 T F 分数 1 作者 张泳 单位 浙大城市学院 字符串常量实质上是一个指向该字符串首字符的指针常量。 T F 分数 1 作者 张泳 单位 浙大城市学院 调用printf函数,%s的格式输出字符串时,字符数组名、字符指针字符串常量都可以作为输出参数。 T F 分数 1 作者 陶煜波 单位 浙江大学 char s[128];使用scanf("%127s", s);输入时,将读取127个字符,并加上\0后返回,这样可以避免字符数组越界存储。 T F 分数 1 作者 陶煜波 单位 浙江大学 输出字符串puts(s);等价于printf("%s\n", s);。 T F 分数 1 作者 陶煜波 单位 浙江大学 int sprintf(char *string, char *format [,argument,...])字符串格式化函数,即将格式化的数据写入某个字符串中,如 char str[128]; int pos = sprintf(str, "%d-%.2f-%s", 123, 3.14159, "abc"); str字符串的内容为"123-3.14-abc",pos的值为输出的字符数12。 T F 分数 1 作者 陶煜波 单位 浙江大学 代码char p[] = "Hello"; strcpy(p, "World");将导致段错误。 T F 分数 1 作者 陶煜波 单位 浙江大学 代码char *p = "Hello"; strcpy(p, "World");将导致段错误。 T F 分数 1 作者 张泳 单位 浙大城市学院 调用strcmp函数比较字符串大小时,通常较长的字符串会较大。 T F 分数 1 作者 陶煜波 单位 浙江大学 mystrlen函数实现了字符串有效长度计算。 int mystrlen(char *s) { char *p = s; while (*++p) ; return p - s; } T F
最新发布
11-28
我们逐题分析并判断正误,给出详细解释。 --- **1. 数组的基地址是在内存中存储数组的起始位置,数组名本身就是一个地址即指针值。** ✅ **答案:T(正确)** **解释:** 在C语言中,数组名表示数组的首地址,也就是第一个元素的地址。如 `int a[10];`,`a` 就是 `&a[0]`,即数组的基地址。虽然数组名不是真正的指针变量(它不能被赋值),但它在大多数表达式中会“退化”为指向首元素的指针。 --- **2. 对于定义 `int a[10], *p = a;` 语句 `p = a + 1;` 和 `a = a + 1;` 都是合法的。** ❌ **答案:F(错误)** **解释:** - `p = a + 1;` 是合法的:因为 `a` 是数组名,在表达式中退化为指针,`a+1` 指向第二个元素,可以赋值给指针 `p`。 - `a = a + 1;` 是非法的:数组名 `a` 是一个左值常量(constant lvalue),不能被赋值。你不能修改数组名所代表的地址。 ```c int a[10]; a++; // 错误!数组名不能自增 ``` --- **3. 两个任意类型的指针可以使用关系运算符比较大小。** ❌ **答案:F(错误)** **解释:** 只有**指向同一个数组或同一对象的指针**之间比较才有定义。不同对象、不同类型(即使强制转换)的指针进行 `<`, `>`, `<=`, `>=` 比较是**未定义行为(UB)或不安全)**。 虽然你可以用 `(char*)p1 < (char*)p2` 比较内存地址,但标准并不保证所有指针都能有意义地比较。特别是不同对象可能位于不同段(现代系统通常平坦内存),但仍建议只对同一数组内的指针做比较。 --- **4. 冒泡排序效率较高,因为它只需要约 $ \frac{n}{2} $ 次比较。** ❌ **答案:F(错误)** **解释:** 冒泡排序的时间复杂度是 $ O(n^2) $,总的比较次数约为 $ \frac{n(n-1)}{2} $,远大于 $ \frac{n}{2} $。说它“效率较高”是错误的,实际上冒泡排序效率较低,仅用于教学。 --- **5. 执行以下代码后,变量x的值为042,变量y的值为87,变量z的值为0x4e。** ```c int a[10] = { '\012', 34, '\x56', 78, 0x910 }, *p = a + 1; int x = *p++; int y = ++*p; int z = *++p; ``` ✅ **答案:T(正确)** **解释:** 先解析初始化: - `'\012'`: 八进制转十进制:$ 1 \times 8 + 2 = 10 $ - `'\\x56'`: 十六进制字符,ASCII码 0x56 = 86 - `0x910` = 2320 所以 `a[]` 实际为: ```c a[0] = 10 a[1] = 34 ← p 初始指向这里 (a+1) a[2] = 86 a[3] = 78 a[4] = 2320 ``` 执行过程: - `int x = *p++;` → 先取 `*p = 34` 赋给 `x`,然后 `p++` 后移 → `p` 指向 `a[2]` - `int y = ++*p;` → `*p` 是 `a[2]=86`,先自增为 `87`,再赋给 `y` - `int z = *++p;` → `p` 先自增指向 `a[3]`,然后解引用得 `78`?等等! ⚠️ 注意:此时 `p` 原本指向 `a[2]`,执行 `++p` 后指向 `a[3]`,`*++p = a[3] = 78` 但题目说 `z = 0x4e`,而 `0x4e = 78` ✅ 所以: - `x = 34` → 八进制写成 `042` 是正确的(因为 `042₈ = 34₁₀`) - `y = 87` - `z = 78 = 0x4e` ✅ 正确。 --- **6. 变量定义如下,指针变量q的值比指针变量p的值大sizeof(char)。** ```c int a[5]; int *p = a; char *q = (char *)p + 1; ``` ✅ **答案:T(正确)** **解释:** - `p = &a[0]`,假设地址是 `X` - `(char *)p` 把整型指针转为字符指针 - `(char *)p + 1` 表示地址加 1 字节(因为 char 是 1 字节) - 所以 `q` 的地址是 `p` 的地址 + 1 字节 - 因此 `q` 的值比 `p` 大 1,而 `sizeof(char)` 是 1 ✅ 正确。 --- **7. 定义数组 `int a[10];`,则表达式 `(int)(&a + 1) - (int)&a` 的值为 4。** ❌ **答案:F(错误)** **解释:** 关键区别: - `&a` 是整个数组的地址,类型是 `int (*)[10]` - `&a + 1` 指向的是跳过整个数组(10个int)后的地址 所以: - `(int)(&a + 1) - (int)&a` 计算的是地址差(字节数) - 差值应为 `10 * sizeof(int) = 10 * 4 = 40`(假设 int 为 4 字节) 如果是 `&a[0] + 1 - &a[0]` 或 `a+1 - a`,才是 1。 ⚠️ 这里是 `&a + 1`,步长是整个数组长度。 所以结果是 40,不是 4。 ❌ 错误。 --- **8. 函数声明和使用代码如下,当调用该函数时,实参数组b的10个元素的值单向传递给形参数组a的10个元素。** ```c int fun(int a[10]); int b[10] = {1,2,3,4,5,6,7,8,9,10}; fun(b); ``` ❌ **答案:F(错误)** **解释:** C语言中,数组参数**不会复制整个数组内容**。所谓“传递数组”实际上是传递首元素地址。形参 `a[10]` 等价于 `int *a`。 因此: - 不是“值传递”,而是传递指针(地址) - 并非“单向传递值”,而是共享内存 —— 如果函数内修改 `a[i]`,会影响原数组 `b` 此外,“单向传递”暗示值拷贝且不可回传,这不符合事实。 ❌ 错误。 --- **9. 形参为数组的函数在编译后都转化为形参为指针的函数,如 `int fun(int a[10])` 转化为 `int fun(int *a)`。** ✅ **答案:T(正确)** **解释:** 这是C语言的核心规则:任何作为函数参数的数组都会退化为指针。无论写成 `int a[]` 还是 `int a[10]`,都等价于 `int *a`。 编译器对此不做区分。 ✅ 正确。 --- **10. 字符串压缩代码如下,`char *q = p;` 是将指针变量p的值(字符串首字符的地址)赋值给指针变量*q。** ```c void zip(char *p) { char *q = p; ...... } ``` ❌ **答案:F(错误)** **解释:** 题目描述:“赋值给指针变量 *q” ❌ 错了! - `char *q = p;` 是声明一个指针 `q`,并将 `p` 的值(地址)赋给 `q` - `*q` 是解引用操作,表示 `q` 指向的内容(字符),而不是指针变量本身 正确说法是:“将 `p` 的值赋给指针变量 `q`” ⚠️ “赋值给 `*q`” 是完全错误的理解。 ❌ 错误。 --- **11. 字符串常量在内存中的存放位置由系统自动安排。** ✅ **答案:T(正确)** **解释:** 字符串常量(如 `"Hello"`)通常存储在只读数据段(`.rodata`),由编译器和链接器决定位置,程序员无法控制具体地址,只能由系统自动管理。 ✅ 正确。 --- **12. 字符串常量实质上是一个指向该字符串首字符的指针常量。** ❌ **答案:F(部分模糊,严格说是错的)** **解释:** 字符串常量的类型是“字符数组”,比如 `"abc"` 类型是 `char [4]`,但在表达式中会退化为 `char *`。 但它**不是指针常量**,而是**数组常量**。它的值是内容,不是地址。 更准确地说:字符串字面量是一个左值,其地址可用,但它本身不是指针如: ```c "hello" // 是数组类型,不是指针 &"hello"[0] // 是指向首字符的指针 ``` 所以说“字符串常量实质上是一个指针常量”是误导性的。 ❌ 错误。 --- **13. 调用printf函数,%s的格式输出字符串时,字符数组名、字符指针字符串常量都可以作为输出参数。** ✅ **答案:T(正确)** **解释:** `%s` 要求传入一个 `char *`,指向以 `\0` 结尾的字符串。 以下都符合: - 字符数组名:`char s[] = "hi"; printf("%s", s);` → `s` 退化为指针 - 字符指针:`char *p = "hi"; printf("%s", p);` - 字符串常量:`printf("%s", "hi");` → 字符串常量也退化为 `char *` 全部合法。 ✅ 正确。 --- **14. `char s[128]; scanf("%127s", s);` 输入时,将读取127个字符,并加上`\0`后返回,避免越界。** ✅ **答案:T(正确)** **解释:** `%127s` 表示最多读取 127 个非空白字符,然后自动添加 `\0`,总共占用 128 字节,正好填满 `s[128]`,不会溢出。 这是防止缓冲区溢出的标准做法。 ✅ 正确。 --- **15. 输出字符串 `puts(s);` 等价于 `printf("%s\n", s);`。** ✅ **答案:T(正确)** **解释:** `puts(s)` 功能: - 输出字符串 `s` - 自动在末尾添加换行符 `\n` - 返回非负值表示成功 `printf("%s\n", s)` 效果相同。 ⚠️ 唯一区别是 `puts` 总是加换行,且不能格式化;但就输出效果而言,等价。 ✅ 正确。 --- **16. `sprintf(str, "%d-%.2f-%s", 123, 3.14159, "abc")` 返回值 pos 为 12,str 内容为 `"123-3.14-abc"`** ✅ **答案:T(正确)** **解释:** 分解输出: - `%d` → `123` → 3 字符 - `-` → 1 字符 - `%.2f` → `3.14` → 4 字符(注意:不是 `3.14159` 四舍五入为 `3.14`) - `-` → 1 字符 - `%s` → `"abc"` → 3 字符 总字符数:3 + 1 + 4 + 1 + 3 = **12** `sprintf` 返回写入的字符数(不含结尾 `\0`),所以 `pos = 12` 字符串为 `"123-3.14-abc"` ✅ 正确。 --- **17. `char p[] = "Hello"; strcpy(p, "World");` 将导致段错误。** ❌ **答案:F(错误)** **解释:** ```c char p[] = "Hello"; // 在栈上分配空间,可读写 strcpy(p, "World"); // 合法,复制到 p 指向的内存 ``` ✅ 这是完全合法的操作。`p` 是局部数组,内容可修改。 不会段错误。 ⚠️ 只有当你试图修改字符串常量时才会出错。 ❌ 所以原命题“将导致段错误”是错的,故答案是 **F(错误)** --- **18. `char *p = "Hello"; strcpy(p, "World");` 将导致段错误。** ✅ **答案:T(正确)** **解释:** ```c char *p = "Hello"; ``` `"Hello"` 是字符串常量,存储在只读内存段。`p` 指向那里。 `strcpy(p, "World")` 试图修改只读内存 → **段错误(Segmentation Fault)** ✅ 正确。 --- **19. 调用 `strcmp` 函数比较字符串大小时,通常较长的字符串会较大。** ❌ **答案:F(错误)** **解释:** `strcmp` 按照**字序(lexicographical)** 比较,逐字符比较 ASCII 值,直到不同或结束。 举: - `"apple"` vs `"app"` → 前三个相同,第四个:`'l' > '\0'` → `"apple" > "app"` ✅ 较长的大 - 但 `"Z"` vs `"aaaaa"` → `'Z' < 'a'`,尽管 `"Z"` 短,却更小 所以“通常较长的字符串会较大”是错误归纳。 ❌ 错误。 --- **20. `mystrlen` 函数实现了字符串有效长度计算。** ```c int mystrlen(char *s) { char *p = s; while (*++p) ; return p - s; } ``` ❌ **答案:F(错误)** **解释:** 问题出在:`while (*++p)` - 它先执行 `++p`,然后判断 `*p` - 初始时 `p = s`,第一次就变成 `p+1`,跳过了首字符 举:`s = "A"`(即 `'A','\0'`) - `p = s` → 指向 `'A'` - `*++p` → `p` 指向 `\0`,`*p == 0` → 循环不进入? - 实际进入循环吗?看逻辑: `while (*++p);` 等价于: ```c do { ++p; } while (*p != '\0'); ``` 不对!`*++p` 是前置自增,先加后判断。 设 `s = "AB"`: - `p = s` (指向 A) - `*++p` → `p` 指向 B,判断 `*p='B'≠0` → 继续 - `*++p` → `p` 指向 `\0`,判断为假 → 退出 - `p - s = 2` → 返回 2?但 `"AB"` 长度是 2,看起来对? 再试空串 `""`: - `p = s` - `*++p` → `p` 指向 `\0` 后一位?其实 `s[0] == '\0'` - `++p` → 指向 `s+1`,`*p == '\0'` → 条件为假,跳出 - `p - s = 1`,但长度应为 0 ❌ 所以对于空字符串,返回 1,明显错误。 正确写法应为: ```c int mystrlen(char *s) { char *p = s; while (*p) p++; return p - s; } ``` 或: ```c while (*(++p)) ; // 仍然错!必须先判断当前 ``` 所以原函数从第二个字符开始判断,漏掉首字符是否为 `\0`,逻辑错误。 ❌ 错误。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值