我正在尝试编写一个执行以下操作的程序:
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
。
而且,一个不太严重的问题(但如果你想成为一名优秀的程序员,需要避免的问题)是,使用字符串长度的函数(如strlen
和strncpy
)通常使用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()
。