gpt4 book ai didi

字符数组自行截断(K&R1-16&1-17)

转载 作者:行者123 更新时间:2023-11-30 15:45:15 37 4
gpt4 key购买 nike

在以下代码中,char 数组在位置 1 和 2 处最多打印 100 个字符,但在位置 3 处仅打印 22 个字符。出现此行为的原因是什么?

#include<stdio.h>
/* print the longest input line */
/*Exercise 1-16. Revise the main routine of the longest-line program so it will correctly print the length of arbitrary long input lines, and as much as possible of the text.*/

#define MAXLENGTH 100

int mygetline(char s[], int limit);
void charcopy(char to[], char from[]);

int main(){
char current[MAXLENGTH];
char longest[MAXLENGTH];
int curlen;
int maxlen;

maxlen = 0;
while( (curlen = mygetline(current, MAXLENGTH)) > 0 ){
if (curlen > 80)
printf("\nvery long:%d; %s\n", curlen, current);//#1# prints 100 digits
if(curlen>maxlen){
maxlen=curlen;
charcopy(longest, current);
printf("\nlonger:%d; %s\n", maxlen, longest);//#2# prints 100 digits
}
}
if (maxlen)//char array seems to truncates itself at scope boundry.
printf("\nlongest:%d; %s\n", maxlen, longest);//#3# prints 22 digits
printf("\nall done!\n");
return 0;
}

int mygetline(char s[], int limit){
int i, c;
for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i)
s[i]=c;
if(c=='\n'){
s[i]=c;
++i;}
else
if(i >= limit-1)
while (((c=getchar()) != EOF) && c != '\n')
++i;
s[i]='\0';
return i-1;
}


void charcopy(char to[], char from[]){
int i;
i=0;
while( (to[i] = from[i]) != '\0'){
++i;}
}

注释中标记为 3 的位置只打印 22 个字符,而不是完整的 100 个字符。这很奇怪。

编辑:根据斯科特的回答,我已将 mygetline 更改为:

int mygetline(char s[], int limit){
int i, c, k;
for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i)
s[i]=c;
if((c=='\n') && (i < limit -1)){
s[i]=c;
++i;}
else{//if we are over the limit, just store the num of char entered without storing chars
k = 0;
while (((c=getchar()) != EOF) && c != '\n')
++k;}
s[i]='\0';
return i+k;
}

可以看出,如果输入超出限制,则输入的字符数将存储在全新的变量 k 中,该变量不会触及数组。我仍然得到最后打印行的截断,并且我得到奇怪的 32770 作为行长度。为什么?可以看出,Array 被婴儿照看、娇惯,只喂了精确数量的炭,仅此而已。

编辑:正如斯科特所指出的,第一个列表的问题是我超出了数组范围。第二个 mygetline 的问题是 k=0; 是在 if else 嵌套内部初始化的。将初始化向上移动并使其对整个函数全局化,似乎解决了第二个问题。

mygetline 工作如下:

int mygetline(char s[], int limit){
int i, c, k;
k=0;
for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i)
s[i]=c;
if((c=='\n') && (i < limit -1)){
s[i]=c;
++i;}
else{//if we are over the limit, just add the num of char entered without storing chars
while (((c=getchar()) != EOF) && c != '\n')
++k;}
s[i]='\0';
return i+k;
}

最佳答案

好吧,关于 C,你需要了解的是它根本不会照顾你。如果您有一个声明为 char foo[4] 的数组并尝试写信给foo[20] ,C根本不会提示。 (如果您写入受限内存(例如 NULL),通常会引发分段冲突,但如果您有权访问该内存,则可以执行任何您想要的操作。)

那么,当您向数组写入超出应有的范围时会发生什么?官方的答案是“未定义的行为”——一个完全通用的笼统答案,并说“这取决于编译器”。然而,在大多数 C 编译器中,它会执行称为破坏堆栈的操作。

您在任何函数(包括 main)中请求的内存都分配在一个很好的单个连贯 block 中。所以在你的 main 函数中,你有 100 个字节 current , longest 为 100 字节, 4 个字节代表 curlen maxlen 和 4 个字节(假设是 32 位整数。它们也可能是 64 位整数,这取决于编译器。)如果您写入 current[123] ,C 会让你这样做 - 并且它会将你写的任何内容放在 longest[23] 的位置上。 。 (通常。同样,这在技术上是未定义的行为,因此不能保证这种情况会发生。)

您的问题是 mygetline 中的行你在哪里设置s[i] = '\0'; 。问题是,你已经让i变得比数组更大。如果您printf("i = %d\n", i);就在该行之前,您会看到 i = 123。您的最后一行没有最大的行那么大,因此您将覆盖 longest 中的数据。您不想覆盖。

有很多方法可以解决这个问题。即,确保当您将某些内容设置为“\0”时,请确保 i <= limit - 1 。 (您可以通过将 s[i] = '\0' 行移动到 while !EOF 行上方并将其设置为 s[limit - 1] 来确保您不会越过。您还需要将 {} 添加到 if 语句一般来说,将它们添加到任何 if 或 while 语句中是一个很好的策略。它们占用一行,但请确保您在正确的位置进行编码。)记住,指令是“获取最大长度,而不是最大字符串。`

如果您确实在前 2 行中看到 100 个字符,我会感到惊讶。据我所知,您应该看到 122。

关于字符数组自行截断(K&R1-16&1-17),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19168245/

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