c-对单词的长度分配有问题



我正在尝试编写一个执行以下操作的程序:

Enter a word: supercalifragilisticoespialidoso
The word's length is: 32.
Enter a smaller number than the length: 23
The word cut on letter 23 is: supercalifragilisticoes.

为此,我正在做:

#include <stdio.h>
#include<string.h>
#define DIM 99
int main() {
char name[DIM], name2[DIM];
int length, length2;
printf("Enter a word: ");
scanf("%s", name);
length = strlen(name);
printf("The word's length is: %dn", length);
printf("Enter a smaller number than the length: ");
scanf("%d", &length2);
name2 = name[length2];
printf("The word cut on the letter %d is: %c", length2, name2);


return 0;
}

但我有

main.c:16:11: error: assignment to expression with array type

问题出在name2 = name[length2]行,这是我发现的创建新的较小单词的方法,但这是不对的。

有人能帮忙吗?

错误在行

name2 = name[length2];

您正试图将一个字符(name中索引length2中的一个)分配给一个数组(name2)。

你真正想做的是:

strncpy(name2, name, length2);
name2[length2] = '';

这将name的第一个length2字节复制到name2中,并为安全起见添加一个终止空字符(如果所有字节都已写入,则strncpy不会执行此操作)。

如果您不打算再次使用name,您还可以完全删除name2,并在name:中添加一个空字符

name[length2] = '';

您还在最后一次printf调用中打印一个带有%c格式说明符的字符串。您应该使用%s

其他答案建议了如何复制输入的初始子字符串,或者如何修改输入字符串。这些都是非常好的方法,在现实世界的程序中都有很多用途。

但是,如果您的程序只需要打印所需的子字符串,则根本不需要进行任何字符串操作。printf可以自己完成这项工作。给定您声明的变量和此代码。。。

scanf("%s", name);
length = strlen(name);
printf("The word's length is: %dn", length);
printf("Enter a smaller number than the length: ");
scanf("%d", &length2);

。。。可以使用printf格式将name打印到一个有界长度字段中,该字段的长度由另一个printf参数给定

printf("%.*sn", length2, name);

这也会在后面添加一条换行符,这通常是人们想要的,但如果你愿意,你可以省略它。

格式化指令中的CCD_;精度";正在通过printf参数为字段指定。其他变体可以直接在格式中表达固定精度。精度的重要性在一定程度上取决于指令类型,但对于s指令,它是从相应的字符串参数打印的最大字符数。

您的代码中有两个主要错误,还有其他一些小错误。

首先,您不能在C中直接分配数组(无论是字符串还是任何其他数组类型);对于以nul终止的char数组(字符串),您可以使用strcpy函数将一个数组复制到另一个数组,或者使用strncpy将一个的部分复制到其他数组(这是您的情况所需的)。

第二,不能使用%c格式说明符打印字符串,需要使用%s

而且,一个不太严重的问题(但如果你想成为一名优秀的程序员,需要避免的问题)是,使用字符串长度的函数(如strlenstrncpy)通常使用size_t类型,而不是int;并且这些要求使用%zu格式说明符来代替%d

这是你的代码的一个版本,可以做你想要的:

#include <stdio.h>
#include<string.h>
#define DIM 99
int main()
{
char name[DIM], name2[DIM] = { 0 }; // Fill with zeros to start, so we will have a nul terminator
size_t length, length2; // Strictly, use "size_t" for "strlen" and "strncpy"
printf("Enter a word: ");
scanf("%s", name);
length = strlen(name);
printf("The word's length is: %zun", length); // Use "%zu" for the "size_t" type
printf("Enter a smaller number than the length: ");
scanf("%zu", &length2); //Again, "%zu" for "size_t"
strncpy(name2, name, length2); // Use this function to copy a substring!
printf("The word cut on the letter %zu is: %s", length2, name2);// Note that you need "%s" to print a string
return 0;
}

您可以在代码中添加一些其他"安全措施",以防止缓冲区溢出和其他故障。一种是将初始字符串输入限制为最多DIM - 1个字符;如果用硬编码值99代替DIM,这将是微不足道的,因为这样就可以使用如下调用:

scanf("%98s", name); // Read at most 98 characters (leaving space for the nul-terminator)

但是,宏DIM不能在带引号的格式字符串中使用。相反,您可以将其值(减1)写入一个单独的字符串中,并将其用作scanf的格式参数;因此,我们替换最初的scanf调用,如下所示:

//  scanf("%s", name); // This has the potential to overrun the "name" array!
char fmt[8];
sprintf(fmt, "%%%ds", DIM - 1); // Write "%98s" into the "fmt" string ...
scanf(fmt, name);               // ...and use that for the "scanf" format

(请注意,有些编译器会警告不要在格式参数中使用字符串文字,有些程序员可能不"赞成"这样做;但是,这是完全合法的C,而且,IMHO是对scanf函数的有效使用。)

任务:

name2 = name[length2];

不具有您所假定的语义。相反,name2是一个数组,而name[length2]是数组name的索引length2处的单个字符

在任何情况下,数组都不是C中的一级数据类型,您不能将一个数组分配给另一个数组(正如您可能打算的那样),更不用说为数组分配char了。

在这里,您可以显式地strncpy()来复制子字符串,但在这种情况下,这可能是不必要的。您可以简单地移除name2阵列并:

printf( "The word cut on the letter %d is: ", length2 ) ;
for( int i = 0; i < length && i < length2; i++ )
{
putchar( name[i] ) ;
}

如果你真的需要存储子字符串,而不是简单地输出它,那么:

int i = 0 ;
for( i = 0; i < length && i < length2; i++ )
{
name2[i] = name[i] ;
}
name2[i] = '' ;

如果length2小于零或大于length(您无法检查),则两者都具有决定性行为的优势。

使用strncpy():

int len = (length2 < 0 || length2 > length) ? 
length : 
length2 ;
strncpy( name2, name, len ) ;
name2[len] = '' ; 

当然,所有这些长度检查在很大程度上都被以第一种方式获取name的安全性所击败。考虑改用fgets(),甚至在循环中使用getchar()

最新更新