Почему argv[0]
не печатает первый символ имени файла вместо всей строки имени файла?
Если argv
является указателем на массив символов, то не следует ли обращаться к нему с результатом [n]
с помощью символа? Если это строка (как предлагает printf(argv[n]
), то почему argv[0][0]
не дает мне первый символ имени файла (компилируется, но вылетает при запуске)?
int main(int argc, char **argv){
printf(argv[0][0]);
while (1){}
return 0;
}
Тип второго аргумента main
, обычно называемого argv
, - это char **
. Он указывает на первый элемент массива char *
. Таким образом, нет, argv
- это нет указатель на массив char
.
Доступ к char **
можно получить с помощью двух операторов индексации, таких как 2D-массив (argv[0][0]
), но 2D-массив - это массив массивов, а не массив указателей. Вы можете найти несколько вопросов по этому поводу здесь, на SO.
Вы можете проверить argv
, как этот for (int i = 0; argv[i] != NULL; ++i) printf("argv[%d]: %s\n", i, argv[i]);
. Обратите внимание, что существует контракт, согласно которому каждый argv[n]
представляет собой массив символов, заканчивающихся на '\0'
, поэтому они являются струны в смысле c. Также есть договор, что последний элемент массива указателей - NULL
. Если вы пишете программу только с этим кодом, произойдет ли сбой? Потому что, конечно, НЕТ, тогда почему бы вам не опубликовать свой код?
@Mawg, как я или компилятор должны знать, является ли ** указателем на указатель или указателем на массив указателей, разве не должно быть ** <имя> [], чтобы указать, что он указывает на массив указателей?
@LukaKostic Компилятору все равно. Вот почему существует неопределенное поведение. Вы тоже заключаете с собой договор об этом. Обозначение char *argv[]
просто указывает читателю, что предполагаемый параметр действительно является массивом указателей, но в конце концов он все равно интерпретируется как char **argv
, и компилятору действительно все равно.
«как я [или компилятор] должен узнать, является ли ** указателем на указатель или указателем на массив указателей» --- вот для чего предназначен argc
.
@meowgoesthedog Я думаю, ОП обеспокоен тем фактом, что char **
может быть чем-то вроде char x = 'a'; char *xx = &x; char **xxx = &xx;
, поэтому xxx
определенно не является указателем на массив указателей символов, или это так?
@LukaKostic Здесь есть хороший урок: код говорит громче, чем слова. Кодирование - это детали, которые упускаются из виду в описании. В этом случае вы концептуально правы, что argv[0][0]
- это первый символ имени файла. Проблема в том, что вы неправильно печатаете этот символ. Всегда размещайте код.
@AndrewHenle Я уже сказал, что argv [n] [n] не работает, а argv [0] [0] компилируется, но дает сбой. Зачем вам для этого нужен код? это прекрасное объяснение проблемы, а не просто "это не работает"
@LukaKostic argv[0][0]
сам по себе не дает сбоев. Это то, как вы его использовали, поэтому код так важен.
@Iharobalasimi одинаково правомерно рассматривать его как указатель на массив только с одним элементом. В конце концов, указатель - это просто адрес блока памяти.
printf(argv[0][0]);
Ваш компилятор не кричит на вас? Либо для указания неправильного типа для первого аргумента, либо для неявного объявления printf
?
Нет. Я использую Visual Studio 2013, я не получаю никаких ошибок / предупреждений, кроме «предупреждение C4013: 'printf' undefined; предполагая, что extern возвращает int», что я не совсем понимаю
@LukaKostic Смотрите cboard.cprogramming.com/c-programming/… - нужно добавить #include <stdio.h>
. Исправление этого приведет к предупреждению об аргументах printf.
Что ж, предупреждение, которое вы получаете делать, объясняет, почему вы не получаете предупреждение о типе аргумента. Вы не предоставили прототип функции для printf
, чтобы сообщить компилятору, что такое аргумент и типы возвращаемого значения. Обычно это делается, помещая строку #include <stdio.h>
в начало программы.
Похоже, кто-то удалил мой комментарий. Не могу придумать почему и предлагаю рассказать мне в чате (или здесь). Я повторю то, что я сказал - здесь есть (или были) некоторые очень заблуждающиеся люди, утверждающие, что нотация **
относится к двумерному массиву - ЭТО НЕ. Имеется ввиду a pointer to a pointer
и не более того. Этот второй указатель мог указывает на массив символов, как в argv
, но может и не быть. Например, int **X
объявляет X
как указатель на указатель на int
- обратите внимание, что здесь нет двух измерений.
Ваш код демонстрирует неопределенное поведение, потому что вы передаете char
функции, которая ожидает указатель.
Чтобы напечатать один символ, у вас есть следующие параметры:
fputc(argv[0][0], stdout);
putchar(argv[0][0]); // Effectively the same as above
printf("%c\n", argv[0][0]);
вы можете добавить больше вариантов printf()
.
Причина сбоя вашего кода заключается в том, что printf(argv[0][0]);
является неопределенным поведением, поскольку функция попытается разыменовать указатель, но вы передали один символ, и значение такого символа будет интерпретировано как адрес памяти.
Вам действительно НУЖНО включить предупреждения компилятора.
Как тут запутаться по адресу? Разве argv [0] [0] не является адресом, а argv [0] [0] - символом?
@LukaKostic В конце концов, char
- это просто интегральный тип, целые числа и указатели взаимозаменяемы в c, но поведение такой сделки не всегда определяется. Более того, если бы адрес был тем, который находится в диапазоне памяти вашей программы, он все равно был бы недействительным, потому что он не указывает на реальную позицию в памяти, или это так? Это не было бы известно заранее, и поэтому это называется неопределенным поведением.
Ясно, что указатели и целые числа не являются взаимозаменяемый в C, но они являются interкабриолет. И некоторые компиляторы выполняют такие преобразования даже без преобразования, которое является расширением (хотя обычно они готовы выдать предупреждение об этом).
Я использую сервер Ubuntu 14 для выполнения и компилятор gcc
для компиляции кода, и argv[n][n]
работал у меня. Взгляните на этот код
// C program to illustrate
// command line arguments
#include<stdio.h>
int main(int argc, char* argv[])
{
int counter;
printf("Program Name Is: %s",argv[0]);
if (argc == 1)
printf("\nNo Extra Command Line Argument Passed Other Than Program Name");
if (argc >= 2)
{
printf("\nChecking double array elements: %c",argv[0][0]);
}
return 0;
}
Выход:
Program Name Is: ./test
Checking double array elements: .
Какую машину вы используете для компиляции и выполнения? может есть какая-то другая ошибка ... проверьте еще раз!
Мне нужен printf ("% c", argv [0] [0]) вместо просто printf (argv [0] [0])
Да, именно так, если вам нужно прочитать char
из строки (массива char
), вы можете сделать это с помощью %c
Поскольку
argv
является указателем на массивchar
указатели.