在向函数传递字符串(C语言)方面存在困惑

3

为什么这个有效:

#include <stdio.h>
void slice(char *st, int m, int n)
{
    int i = 0;
    while ((i + m) < n)
    {
        st[i] = st[i + m];
        i++;
    }
    st[i-1] = '\0';
}

int main()
{
    char st[] = "Hello";
    slice(st, 1, 6);
    printf("The value of string is %s\n", st);
    return 0;
}

这并不会:
#include <stdio.h>
void slice(char *st, int m, int n)
{
    int i = 0;
    while ((i + m) < n)
    {
        st[i] = st[i + m];
        i++;
    }
    st[i-1] = '\0';
}

int main()
{
    char*st = "Hello";
    slice(st, 1, 6);
    printf("The value of string is %s\n", st);
    return 0;
}

起初,我使用以下代码初始化了字符串:

  • char st[]="Hello";(使用数组)

后来,我又使用了以下代码:

  • char*st="Hello";(使用指针)

我有些混淆了这两种初始化方式之间的关键区别。使用char st[]="Hello";char*st = "Hello";声明字符串有什么区别呢?


2
后者指向只读常量内存,前者将数据复制到读/写内存。 - Sami Kuhmonen
3个回答

3
使用 char st[] = "Hello";st[] 是一个可修改的字符数组。调用 slice(st, 1, 6); 函数将数组 st 转换为指向其第一个元素的指针。然后,slice() 函数接收该指针,指向可修改的字符。

使用 char *st = "Hello";st 是指向字符串字面值 "Hello"指针。调用 slice(st, 1, 6); 函数会接收指针的副本——指向字符串字面值的指针。在 slice() 函数内部,代码 st[i] = ... 试图修改一个字符串字面值,这是未定义行为(UB)。它可能起作用,也可能失败,今天可能工作,明天可能失败- 这没有定义。

不要尝试修改字符串字面值


... 将字符串传递给函数 ...

在两种情况下,代码都没有传递一个字符串slice() 函数,而是传递了指向字符串的指针。了解这个微妙的区别有助于理解实际发生了什么。


2

这是C语言旧语法的产物:

char * s = "Hello world!";

这是一个指向常量内存的非const字符指针。虽然语法上仍然允许,但该字符串并不是可变对象。严谨来说,它应该被写成:

const char * s = "Hello world!";

相比之下:
char s[] = "Hello world!";

该函数会分配一个本地(在堆栈上)的可变数组,并将字符串数据复制到其中(从非可变副本存储在内存的任何位置)。然后,您的函数可以随意操作本地字符串副本。


1

类型char[]与类型char*不同(char*是一个变量-int,但char[]是一个不可变的数组)。然而,数组名称可以用作指向数组的指针。

因此,我们可以说st[]在技术上类似于*str。

您代码第二个版本中的问题

如果您有只读字符串,则可以使用const char* st = "hello";或简单地使用char* st = "hello";。因此,该字符串很可能存储在只读内存位置,并且您将无法修改它。

但是,如果您想要能够修改它,请使用malloc函数:

char *st= (char*) malloc(n*sizeof(char)); /* n-The initial size that you need */
// ...
free(st);

为了为st分配内存,需要计算字符数("hello"-strlen(st)=5),再加上一个终止的空字符。像scanf和strcpy这样的函数会自动添加空字符;

因此代码变为:

#include <stdio.h>
void slice(char *st, int m, int n)
{
    int i = 0;
    while ((i + m) < n)
    {
        st[i] = st[i + m];
        i++;
    }
    st[i-1] = '\0';
}

int main()
{
    char *st =malloc(6*sizeof(char))  ;
    const char *cpy="hello";
    strcpy(st, cpy); /* copies the string pointed by cpy (including the null character) to the st. */
    slice(st, 1, 6);
    printf("The value of string is %s\n", st);
    return 0;
}
  1. 您可以使用for循环或scanf()函数来填充字符串。

  2. 如果分配的内存较大,必须在代码末尾使用free(st);释放内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接