gpt4 book ai didi

c - 为什么即使我不尝试修改字符串,也会在 C 中修改它?

转载 作者:行者123 更新时间:2023-12-04 10:00:14 25 4
gpt4 key购买 nike

我正在尝试解决 K&R C 第二版中的练习 1-19。 “编写一个函数 reverse 来反转字符串 s。用它来编写程序,一次反转输入一行。”

我的解决方案需要两个输入字符串 st . s是来源和t是目标。并复制源 s 中的数据至 t .我能够解决这个问题,但我很难理解为什么源字符串 s被修改,即使它不在等号运算符的左侧。

#include <stdio.h>

/* Solution to Exercise 1-19. Chapter 1 */

#define MAXLENGTH 10

int getln(char s[], int lim);
void reverse(char s[], char t[]);

int main()
{
int i, len;

char s[MAXLENGTH]; /* original string */
char t[MAXLENGTH]; /* reversed string */

while ((len = getln(s, MAXLENGTH)) > 0) {
printf("before reverse: %s", s);
reverse(s,t);
printf("reversed string: %s\n", t);
printf("after reverse: %s", s);
}
return 0;
}

/* getln: read a line into s, return length */
int getln(char s[], int lim)
{
int c, i, l;

l = 0;
for (i = 0; ((c = getchar()) != EOF) && (c != '\n'); ++i) {
if (i < (lim - 1)) {
s[l] = c;
++l;
}
}

if (c == '\n') {
s[l] = c;
++l;
}

s[l] = '\0';
return l;
}

/* reverse: reverses s to target t */
void reverse(char s[], char t[])
{
int i, j;
for (i = 0; s[i] != '\0'; ++i)
;
--i;
if (s[i] == '\n') {
--i;
}
for (j = 0; i >= 0; ++j) {
t[j] = s[i];
--i;
}
t[j] = '\0';
}


测试用例:
$ ./a.out < testdata 
before reverse: abcdefghi
reversed string: ihgfedcba
after reverse: abcdefghi
ihgfedcba$

文件 testdata 的内容:
$ cat testdata 
abcdefghijklmnopqrstuvwxyz
$

最佳答案

函数getln有一个bug为了简化函数的分析,我们假设 lim等于 2。

然后在这个循环中

  l = 0; 
for (i = 0; ((c = getchar()) != EOF) && (c != '\n'); ++i) {
if (i < (lim - 1)) {
s[l] = c;
++l;
}
}

你可以写 lim-1只有一个字符的字符。当用户按下将换行符 '\n' 发送到输入缓冲区的 Enter 键时,循环停止迭代。 .

所以最后读取的字符是换行符 '\n' .这个字符存储在循环后的字符串中
  if (c == '\n') {
s[l] = c;
++l;
}

现在极限已经用完了。设置传入的字符数组的两个字符。

但是在接下来的声明中
  s[l] = '\0';
l时有超出限制的内存访问等于 2。

就这些。该函数调用未定义的行为,前提是参数 lim 的值等于传递的字符数组的大小。终止零字符 '\0'写入字符数组外的内存中,以后可以覆盖。

我将按以下方式定义函数,如下面的演示程序所示。
#include <stdio.h>

size_t getln( char s[], size_t n )
{
size_t i = 0;

if ( n )
{
int c;

while ( i + 1 < n && ( c = getchar() ) != EOF && c != '\n' )
{
s[i++] = c;
}

if ( c == '\n' && i + 1 < n ) s[i++] = c;

s[i] = '\0';
}

return i;
}

int main(void)
{
enum { N = 10 };
char s[N];

while ( getln( s, N ) ) printf( "\"%s\"\n", s );

return 0;
}

如果进入
abcdefghijklmnopqrstuvwxyz

那么程序输出将是
"abcdefghi"
"jklmnopqr"
"stuvwxyz
"

那只是最后输入的字符串包含换行符。

注意练习里有写

Write a function reverse that reverses the character string s.



这意味着您需要反转原始字符串本身,而不是将其以相反的顺序处理到另一个字符数组。

这样的函数可以看起来像下面这样
#include <stdio.h>

char * reverse( char *s )
{
size_t n = 0;

while ( s[n] != '\0' ) n++;

if ( n && s[n-1] == '\n' ) --n;

for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n-i-1];
s[n-i-1] = c;
}

return s;
}

size_t getln( char s[], size_t n )
{
size_t i = 0;

if ( n )
{
int c;

while ( i + 1 < n && ( c = getchar() ) != EOF && c != '\n' )
{
s[i++] = c;
}

if ( c == '\n' && i + 1 < n ) s[i++] = c;

s[i] = '\0';
}

return i;
}

int main(void)
{
enum { N = 10 };
char s[N];

while ( getln( s, N ) ) printf( "\"%s\"\n", reverse( s ) );

return 0;
}

如果输入是
abcdefghijklmnopqrstuvwxyz

那么程序输出是
"ihgfedcba"
"rqponmlkj"
"zyxwvuts
"

如果要删除换行符 '\n'来自函数内的字符串 reverse然后替换这个语句
    if ( n && s[n-1] == '\n' ) --n;

对于这个
    if ( n && s[n-1] == '\n' ) s[--n] = '\0';

关于c - 为什么即使我不尝试修改字符串,也会在 C 中修改它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61844757/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com