2013-12-16 6 views
6
#include<iostream> 
#include<string.h> 
#include<stdio.h> 


int main() 
{ 
    char left[4]; 
    for(int i=0; i<4; i++) 
    { 
     left[i]='0'; 
    } 
    char str[10]; 
    gets(str); 
    strcat(left,str); 
    puts(left); 
    return 0; 
} 

для любого ввода он должен конкатенировать 0000 с этой строкой, но на одном ПК он показывает знак бриллианта между «0000» и входной строкой ...!Моя программа дает разные результаты на разных машинах ..!

+5

Вы находитесь за пределами своего буфера. Это действительно неопределенное поведение. –

+3

Функция [получает()] (http://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used) является устаревшей и опасной, дон Не используйте его. – this

+2

left - это не строка с нулевым концом. Вам необходимо определить символ слева [5]; , а затем добавить после петли влево [4] = 0; // note 0, а не '0' –

ответ

6

Вы добавляете символ девяти (или более, gets не имеющих границ) в строку с тремя символами (которая содержит четыре символа и без терминатора строк). Никакого прекращения строки. Поэтому, когда вы печатаете с использованием puts, он будет продолжать печатать, пока не найдет символ окончания строки, который может быть в любом месте в памяти. Короче говоря, пример школьной книги переполнения буфера, а переполнение буфера обычно ведет к неопределенным поведением, что и есть то, что вы видите.

В C и C++ все строки в стиле C должны быть завершены. Они заканчиваются специальным символом: '\0' (или простой ASCII-ноль). Вы также должны предоставить достаточно места для строки назначения в своем вызове strcat.


Правильная, рабочая программа:

#include <stdio.h> 
#include <string.h> 
#include <errno.h> 

int main(void) 
{ 
    /* Size is 4 + 10 + 1, the last +1 for the string terminator */ 
    char left[15] = "0000"; 
    /* The initialization above sets the four first characters to '0' 
    * and properly terminates it by adding the (invisible) '\0' terminator 
    * which is included in the literal string. 
    */ 

    /* Space for ten characters, plus terminator */ 
    char str[11]; 

    /* Read string from user, with bounds-checking. 
    * Also check that something was truly read, as `fgets` returns 
    * `NULL` on error or other failure to read. 
    */ 
    if (fgets(str, sizeof(str), stdin) == NULL) 
    { 
     /* There might be an error */ 
     if (ferror(stdin)) 
      printf("Error reading input: %s\n", strerror(errno)); 
     return 1; 
    } 

    /* Unfortunately `fgets` may leave the newline in the input string 
    * so we have to remove it. 
    * This is done by changing the newline to the string terminator. 
    * 
    * First check that the newline really is there though. This is done 
    * by first making sure there is something in the string (using `strlen`) 
    * and then to check if the last character is a newline. The use of `-1` 
    * is because strings like arrays starts their indexing at zero. 
    */ 
    if (strlen(str) > 0 && str[strlen(str) - 1] == '\n') 
     str[strlen(str) - 1] = '\0'; 

    /* Here we know that `left` is currently four characters, and that `str` 
    * is at most ten characters (not including zero terminaton). Since the 
    * total length allocated for `left` is 15, we know that there is enough 
    * space in `left` to have `str` added to it. 
    */ 
    strcat(left, str); 

    /* Print the string */ 
    printf("%s\n", left); 

    return 0; 
} 
+3

Я бы назвал его «школьной книгой пример переполнения буфера * ". Меньше общего срока. – jrok

0

Проблема № 1 - не является юридическим строка:

char left[4]; 
for(int i=0; i<4; i++) 
{ 
    left[i]='0'; 
} 

Строка должна заканчиваться нулевым полукокса, '\0' не '0'. Это приводит к тому, что вы описываете.

Проблема №2 - fgets. Вы используете его на небольшом буфере. Очень опасно.

Задача № 3 - strcat. Тем не менее, снова пытается заполнить супермаленький буфер, который должен был быть заполнен дополнительной строкой.

Этот код выглядит как приглашение на переполнение буфера.

0

В C то, что мы называем строкой, является массив символов с нулевым завершающим символом. Все функции в библиотеке string.h основаны на этом нулевом значении в конце массива символов. Ваш массив символов не завершен нулем и, следовательно, не строка, поэтому вы не можете использовать функцию strcat для строковой библиотеки здесь.

2

Есть две проблемы.

Во-первых, left не nul-terminated, поэтому strcat в конечном итоге будет смотреть за пределы массива для подходящего места для добавления символов. Поместите номер '\0' в конец массива.

Во-вторых, left не достаточно большой, чтобы удерживать результат звонка до strcat. Должно быть достаточно места для результирующей строки, включая терминатор nul. Поэтому размер left должен составлять не менее 4 + 9, чтобы разрешить три символа (плюс nul terminator), с которых начинается left, и 9 символов, исходящих от str (при условии, что gets не вызвало переполнения).

Каждая из этих ошибок приводит к неопределенному поведению, которое учитывает разные результаты на разных платформах.

1

Я не знаю, почему вы беспокоитесь о включении <iostream>, так как вы не используете какие-либо функции C++ в своем коде. Вся ваша программа будет гораздо короче, если у вас:

#include <iostream> 
#include <string> 

int main() 
{ 
    std::string line; 
    std::cin >> line; 
    std::cout << "You entered: " << line; 
    return 0; 
} 

С std::string будет нулевым байтом, нет никаких причин, чтобы заставить его быть 4-нулем.

Смежные вопросы