繁体   English   中英

使用 C 中的指针将大写转换为小写

[英]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部分中创建的。你这样做无法更改该数据-您现在知道尝试时会发生什么:)

问题中编写的代码还显示了指针firstsecond实际指向的内容的混淆。 通过将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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM