[英]Converting Upper Case to Lower Case using pointers in C
我一直在尝试使用指针将大写字母更改为小写字母,但我不断遇到分段错误。 这是我的源代码:
#include <stdlib.h>
#include <string.h>
char *changeL(char *s);
char *changeL(char *s)
{
char *upper = s;
for (int i = 0; upper[i] != '\0'; i++)
{
if (upper[i] >= 'A' && upper[i] <= 'Z')
{
upper[i] += 32;
}
}
printf("%s\n", upper);
return upper;
}
int main()
{
char *first;
char *second;
first = "HELLO My Name is LoL";
printf("%s\n", first);
second = changeL(first);
printf("There is no error here\n\n");
printf("%s\n", second);
return 0;
}
使用 gdb 我发现 seg 错误出现在“upper[i] += 32;”中。 我不明白为什么会出现段错误。
“HELLO My Name is LoL”是永恒的记忆。 你不能改变它。 但是,您将指向此内存的指针(首先)传递给试图更改它的函数。 因此,您遇到了分段错误。 您应该将此字符串复制到内存缓冲区。 喜欢
char buffer[] = "HELLO My Name is LoL";
然后将缓冲区传递给changeL
除了@Alex在他的回答中正确指出的内容之外,还有一些注意事项。 第一的
char *changeL(char *s);
char *changeL(char *s)
{
....
}
如果函数在下面一行,则函数之前不需要原型。 原型用于通知它下面的代码原型所描述的功能存在并且在别处定义。 如果您在原型的正下方定义函数,它会使原型变得无关紧要。
第二,正如亚历克斯的回答中所指出的,在绝大多数系统上,字符串文字,例如char *s = "Something Here";
"Something Here"
的 "Something Here" 。 是不可变的并且驻留在只读内存中,任何修改字符串文字的尝试通常都会导致 SegFault。
相反,您需要创建一个可以修改的字符数组,例如
char first[] = "HELLO My Name is LoL";
或者使用 C99+,您可以使用复合文字first
初始化为指向char
数组的指针,例如
char *first = (char[]){ "HELLO My Name is LoL" };
在上述两种情况下, first
指向的字符都是可以修改的。
每条评论添加
"can you also explain to him why is he getting segfault at upper[i] += 32;"
是的。 如上所述,当您在几乎每个当前系统上初始化指向字符串文字的指针时(古代系统对只读内存没有区别或保护——所有内存都是可写的)。 在当前,创建字符串文字(例如"foo"
)会在内存中创建无法修改的字符串。 (对于 ELF 可执行文件,通常位于可执行文件的.rodata
部分中——仔细剖析".ro...data"
意思是"read-only data"
)
当尝试更改无法修改的数据时,通常会导致分段错误,因为您试图写入只读段内的地址。 (因此是 SegFault 的分段错误)
在上面的代码中,最初是用
first = "HELLO My Name is LoL";
如果你编译成程序集(在 Linux 上,例如gcc -S -masm=intel -o mysaved.asm myfile.c
你会看到字符串"HELLO My Name is LoL"
实际上是在.rodata
部分中创建的。你这样做无法更改该数据-您现在知道尝试时会发生什么:)
问题中编写的代码还显示了指针first
和second
实际指向的内容的混淆。 通过将changeL
的返回值分配给second
,不会为second
创建新的内存。 这与简单地分配second = first;
在main()
中。 second
只是一个单独的指针,它指向first
引用的同一内存。 更简洁的代码版本是:
#include <stdio.h>
void changeL (char *s)
{
for (int i = 0; s[i]; i++)
if (s[i] >= 'A' && s[i] <= 'Z')
s[i] += 32;
}
int main (void)
{
char first[] = "HELLO My Name is LoL";
char *second = first;
printf("%s\n", first);
changeL(first);
printf("%s\n", second);
return 0;
}
(注意:原代码中的两个头文件都是不必要的, <stdio.h>
是唯一需要的头文件)
为了说明second
简单地指向first
:
示例使用/输出
$./bin/chars
HELLO My Name is LoL
hello my name is lol
此代码仅输出字符串中的小写字母
#include<stdio.h>
#include<string.h>
int main()
{
char b[50];
printf("String=");
scanf("%[a-z]",b);
printf("%s",b);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.