Защита только предотвращает включение заголовка дважды в один и тот же блок компиляции.
Когда вы компилируете src1.o
и src2.o
, каждый из них будет содержать определение my_var
. Когда вы связываете их для создания a.out
, компилятор не может объединить эти определения (даже если они идентичны) и не работает.
Что вы хотите сделать, это объявить my_var
как extern :
---- head.h ----
#ifndef _HEAD_H_
#define _HEAD_H_
extern int my_var;
#endif
---- my_var.c ----
#include "head.h"
int my_var = 100;
Затем скомпилируйте все исходные файлы:
g++ -c my_var.cpp -o my_var.o
g++ -c src1.cpp -o scr1.o
g++ -c src2.cpp -o src2.o
g++ -o a.out my_var.o src2.o src1.o
Таким образом, my_var
будет объявлен в каждом файле, но будет определен только ] в my_var.o
. Здесь важная разница. Попробуйте пропустить ссылку my_var.o
, вы увидите, что компилятор должен сказать:)
char a[50][50]
объявляет a
как массив с 50 элементами массивов с 50 элементами char
. Это означает, что каждый a[i]
является массивом с 50 элементами char
. Это будет размечено в памяти как:
+---+
a: | | a[0][0]
+---+
| | a[0][1]
+---+
| | a[0][2]
+---+
...
+---+
| | a[0][49]
+---+
| | a[1][0]
+---+
| | a[1][1]
+---+
...
+---+
| | a[1][49]
+---+
| | a[2][0]
+---+
...
Этот код хранит до 50 строки , каждый до 49 символов в длину, в a
(IOW, каждый a[i]
может сохранить 49 символьных строк). В C строка является последовательностью символьных значений включая 0-значный разделитель. Например, строка "hello"
, представлен как последовательность {'h', 'e', 'l', 'l', 'o', 0}
. То запаздывание 0
метки конец строки. Строковые функции обработки и функции вывода как [1 113] и printf
с %s
потребность спецификатора, что 0 разделителей для обработки строки правильно.
Строки хранятся в массивах типа символов, или char
(для ASCII, UTF-8 или наборов символов EBCDIC) или wchar_t
для "широких" строк (наборы символов, которые требуют, чтобы больше чем приблизительно 8 битов закодировали). N-символьная-строка требует массива, который это по крайней мере [1 142] элементы N+1, широкие для составления 0 разделителей.
, Если это не операнд sizeof
или унарный &
оператор или является строковым литералом, раньше инициализировал массив типа символов, , выражение типа "массив N-элемента [1 120]" будет преобразовано ("затухают") к выражению типа "указатель на [1 121]", и значение выражения будет адресом первого элемента массива.
, Когда Вы звоните
gets( a[i] );
, выражение a[i]
преобразовывается из типа "массив с 50 элементами [1 123]" к "указателю на [1 124]", и значение выражения является адресом первого элемента массива (&a[i][0]
) <глоток> 1 глоток>. gets
считает символы из стандартного входа и сохранит их к массиву, запускающемуся в том адресе. Обратите внимание, что gets
больше не часть стандартной библиотеки для C - она была удалена в версии 2011 года стандарта, потому что это небезопасно. C не требует никакого вида границ, проверяющих доступы к массиву - если Вы введете в большем количестве символов, чем целевой буфер измерен для содержания (в этом случае, 50), те дополнительные символы будут записаны в память сразу после последнего элемента массива, который может вызвать все виды погрома. Переполнение буфера является популярным вредоносным использованием. Необходимо заменить эти gets
вызов с [1 154]
fgets( a[i], 50, stdin );
, который считает до 49 символов в [1 129] от стандартного входа. Обратите внимание, что любые избыточные символы оставляют во входном потоке.
кроме того, поведение [1 130] не определяется для входных потоков <глоток> 2 глоток> - там бесполезно, безопасен, портативный способ очистить избыточный вход кроме считать его с помощью [1 131] или fgetc
.
<час> <глоток>
a
с [1 134] до [1 135] - в этом случае, a[i]
имеет тип char
, не char *
, и значение [1 139] не адрес . глоток>
char a[50][50]
объявляет a
быть массивом 50 массивов 50 char
.
Затем a[0]
массив 50 char
и так a[1]
, a[2]
. a[3]
, и так далее [до 118]. Существует 50 отдельных массивов, и каждый из них имеет 50 char
.
С тех пор a[0]
массив 50 char
, a[0][0]
char
. В целом, a[i][j]
символ j
из массива i
.
gets(a[i])
говорит, чтобы считать символы из входа и поместить их в [1 118]. Чтобы это работало, a[i]
должен быть массив [1 120] — gets
чтения несколько символов и помещает их в массив. Если бы a[i]
был отдельный символ, [то 1123] не мог бы работать.
, Хотя gets(a[i])
говорит для помещения символов в [1 125], это работает путем передачи адреса вместо того, чтобы передать массив. Когда массив используется в выражении кроме как операнд [1 126], или операция взятия адреса &
, C автоматически преобразовывает его в указатель на его первый элемент. С тех пор a[i]
массив, он автоматически преобразовывается в указатель на свой первый элемент (указатель на [1 129]). gets
получает этот указатель и использует его для заполнения символов, которые это читает из стандартного входного потока.
Та программа, кажется, хранит n
имена в массиве a
. Это сначала просит количество имен и затем имен. Метод char *gets(char *str)
хранилища каждая различная строка в записи a
.
n
имеет 2 размера. Первое относится к количеству имен, и второе для длины каждого имени. Что-то как n[number_of_names][lenght_of_name]
Однако это, вероятно, откажет, если пользователь обеспечит n> 50, или если имя содержит больше чем 50 символов.
кроме того, gets()
опасно. См. это другое сообщение .
РЕДАКТИРОВАНИЕ: Изменение a
к размерам заставляет программу попытаться сохранить целую строку в символе, следовательно ошибка
В основном в C это показывает, что массив длины от 0 до 50 из этого содержит символьное значение 50 в каждой ячейке массива