я практиковал основы, поэтому я пишу код, чтобы спросить об имени пользователя, а затем я хотел напечатать имя пользователя посимвольно, затем полное имя и его длину, а в конце четные числа символы имени пользователя, такие как 2-й, 4-й и т. д. у меня есть две проблемы: сначала длина имени переменной становится нулевой, а затем для цикла моей второй проблемой были четные символы, так как я тоже получаю нечетные
я ввел имя пользователя: Джеймс я ожидал, что результат будет:
j
5
a
5
m
5
e
5
s
5
hello james , your name has 5 characters
ae
#include <stdio.h>
#include <cs50.h>
#include <string.h>
int main(void)
{
string name = get_string("whats your name ? ");
int x = strlen(name);
char new[4] = "";
for (int i = 0 ; i < x ; i++)
{
printf("%c\n" ,name[i] );
if ( (i+1) % 2 == 0)
{
strcat(new,&name[i]);
}
printf("%i\n",x);
}
printf("hello %s ,your name has %i characters \n", name,x);
printf("%s\n",new);
}
whats your name ? james
j
5
a
0
hello james ,your name is 0 characters long
ames
Чего вы ожидаете от strcat(new,&name[i]);? Такое ощущение, что вы пытаетесь добавить один символ к new, но на самом деле эта строка делает не это.





Основная проблема заключается в том, что буфер new недостаточно велик для хранения данных, которые вы в него записываете. Я подозреваю, что основная путаница связана с неправильным использованием strcat. Когда вы пишете strcat(new,&name[i]);, он не копирует ни одного символа в конец new. Если name — это «james», а i — это 2, то &name[i] — это адрес «m», а strcat пытается скопировать строку «mes» в конец new. Если вы просто хотите скопировать один символ, strcat — неправильный инструмент. ИМО, эта путаница усугубляется использованием string typedef, единственной целью которого является запутать учащихся. Прекратите использовать string и вместо этого используйте char *. Вы должны понимать эту деталь, если хотите когда-нибудь понять C.
Если вы хотите перебрать строку и скопировать каждый второй символ в массив, возможно, вам нужно что-то вроде ниже. Обратите внимание, что вы должны проверить границы массива, если вы используете неизвестный ввод.
#include <stdio.h>
#include <string.h>
int
main(int argc, char **argv)
{
char *name = argc > 1 ? argv[1] : "james";
int length = strlen(name);
char new[128] = "";
char *d = new;
/*
Checking the parity of i inside the loop is a code smell, but
we leave this as dead code for comparison to the original. Simply
skipping the unwanted indices is done below the dead code.
for( int i = 0; i < length && i < sizeof new - 1; i += 1 ){
if ( (i+1) % 2 == 0 ){
*d++ = name[i];
}
}
*/
for( int i = 1; i < length && i < sizeof new - 1; i += 2 ){
*d++ = name[i];
}
*d = '\0';
printf("hello %s, your name has %i characters \n", name, length);
printf("%s\n", new);
return 0;
}
Многие сочли бы более естественным написать цикл примерно так:
char *end = new + min(length, sizeof new);
for( name += 1; d < end; name += 2 ){
*d++ = *name;
}
и избавиться от всей индексации. Обратите внимание, что для вычисления минимума требуется определение min, и он теряет начало исходного name, поэтому вам нужно будет отслеживать начало имени или использовать другую переменную для цикла. Вместо индексации вы просто отслеживаете три указателя; один к символу, который вы хотите скопировать, один к месту назначения, в которое вы хотите его скопировать, и один к концу буфера назначения, чтобы вы не прошли мимо него.
Указание людям, обучающимся через CS50, не использовать string, вероятно, приведет к путанице, поскольку именно этому учит курс и что использует заголовок cs50.h.
... что является одним из худших недостатков CS50. string typedef глубоко укоренился в курсе, но по своей сути он сбивает с толку и даже вводит в заблуждение. Думаю, в CS50 есть что-то, что может понравиться, но в целом мне сложно его рекомендовать.
Вы ввели строку "james", содержащую 6 символов, включая завершающий нулевой символ '\0'.
whats your name ? james
И вы объявили массив символов, который состоит только из 4 элементов.
char new[4] = "";
В этом операторе if
if ( (i+1) % 2 == 0)
{
strcat(new,&name[i]);
}
когда, например, i равно 1, строка, на которую указывает выражение указателя name + 1, добавляется к массиву символов new.
strcat(new,&name[i]);
Это следующая строка (представленная в виде массива символов) { 'a', 'm', 'e', 's', '\0' }. Как видно, строка содержит 5 символов, включая завершающий нулевой символ '\0'. В результате этот вызов strcat приводит к перезаписи памяти вне массива new, что приводит к неопределенному поведению.
Нет необходимости использовать функцию strcat, потому что вместо сохранения только одного символа в массиве new функция пытается добавить целую подстроку.
Вы могли бы написать, например
for (int i = 0 ; i < x ; i++)
{
printf("%c\n" ,name[i] );
if ( (i+1) % 2 == 0)
{
new[i / 2] = name[i];
}
printf("%i\n",x);
}
Обратите внимание, что массив new будет содержать строку, так как все его элементы изначально были инициализированы нулями в объявлении массива
char new[4] = "";
С другой стороны, использование магического числа 4 в объявлении массива небезопасно. Вместо этого вы можете объявить, например, массив переменной длины, например
int x = strlen(name);
char new[x / 2 + 1];
memset( new, 0, x / 2 + 1 );
В этом случае ваша программа будет работать, даже если пользователь введет более длинное имя.
Шаг 1. Прекратите использовать
string. Это ненужное запутывание, которое вызывает путаницу, а не проясняет что-либо.