Как argv представляет собой массив строк, если это массив символов?

Почему argv[0] не печатает первый символ имени файла вместо всей строки имени файла?

Если argv является указателем на массив символов, то не следует ли обращаться к нему с результатом [n] с помощью символа? Если это строка (как предлагает printf(argv[n]), то почему argv[0][0] не дает мне первый символ имени файла (компилируется, но вылетает при запуске)?

int main(int argc, char **argv){

    printf(argv[0][0]);

    while (1){}
    return 0;
}

Поскольку argv является указателем на массив charуказатели.

Weather Vane 10.08.2018 14:01

Тип второго аргумента main, обычно называемого argv, - это char **. Он указывает на первый элемент массива char *. Таким образом, нет, argv - это нет указатель на массив char.

John Bollinger 10.08.2018 14:01

Доступ к char ** можно получить с помощью двух операторов индексации, таких как 2D-массив (argv[0][0]), но 2D-массив - это массив массивов, а не массив указателей. Вы можете найти несколько вопросов по этому поводу здесь, на SO.

John Bollinger 10.08.2018 14:06

Вы можете проверить argv, как этот for (int i = 0; argv[i] != NULL; ++i) printf("argv[%d]: %s\n", i, argv[i]);. Обратите внимание, что существует контракт, согласно которому каждый argv[n] представляет собой массив символов, заканчивающихся на '\0', поэтому они являются струны в смысле c. Также есть договор, что последний элемент массива указателей - NULL. Если вы пишете программу только с этим кодом, произойдет ли сбой? Потому что, конечно, НЕТ, тогда почему бы вам не опубликовать свой код?

Iharob Al Asimi 10.08.2018 14:08

@Mawg, как я или компилятор должны знать, является ли ** указателем на указатель или указателем на массив указателей, разве не должно быть ** <имя> [], чтобы указать, что он указывает на массив указателей?

Luka Kostic 10.08.2018 14:10

@LukaKostic Компилятору все равно. Вот почему существует неопределенное поведение. Вы тоже заключаете с собой договор об этом. Обозначение char *argv[] просто указывает читателю, что предполагаемый параметр действительно является массивом указателей, но в конце концов он все равно интерпретируется как char **argv, и компилятору действительно все равно.

Iharob Al Asimi 10.08.2018 14:16

«как я [или компилятор] должен узнать, является ли ** указателем на указатель или указателем на массив указателей» --- вот для чего предназначен argc.

meowgoesthedog 10.08.2018 14:18

@meowgoesthedog Я думаю, ОП обеспокоен тем фактом, что char ** может быть чем-то вроде char x = 'a'; char *xx = &x; char **xxx = &xx;, поэтому xxx определенно не является указателем на массив указателей символов, или это так?

Iharob Al Asimi 10.08.2018 14:21

@LukaKostic Здесь есть хороший урок: код говорит громче, чем слова. Кодирование - это детали, которые упускаются из виду в описании. В этом случае вы концептуально правы, что argv[0][0] - это первый символ имени файла. Проблема в том, что вы неправильно печатаете этот символ. Всегда размещайте код.

John Kugelman 10.08.2018 14:22

@AndrewHenle Я уже сказал, что argv [n] [n] не работает, а argv [0] [0] компилируется, но дает сбой. Зачем вам для этого нужен код? это прекрасное объяснение проблемы, а не просто "это не работает"

Luka Kostic 10.08.2018 14:22

@LukaKostic argv[0][0] сам по себе не дает сбоев. Это то, как вы его использовали, поэтому код так важен.

Iharob Al Asimi 10.08.2018 14:23

@Iharobalasimi одинаково правомерно рассматривать его как указатель на массив только с одним элементом. В конце концов, указатель - это просто адрес блока памяти.

meowgoesthedog 10.08.2018 14:25
printf(argv[0][0]); Ваш компилятор не кричит на вас? Либо для указания неправильного типа для первого аргумента, либо для неявного объявления printf?
Gerhardh 10.08.2018 15:07

Нет. Я использую Visual Studio 2013, я не получаю никаких ошибок / предупреждений, кроме «предупреждение C4013: 'printf' undefined; предполагая, что extern возвращает int», что я не совсем понимаю

Luka Kostic 10.08.2018 15:11

@LukaKostic Смотрите cboard.cprogramming.com/c-programming/… - нужно добавить #include <stdio.h>. Исправление этого приведет к предупреждению об аргументах printf.

John Kugelman 10.08.2018 15:25

Что ж, предупреждение, которое вы получаете делать, объясняет, почему вы не получаете предупреждение о типе аргумента. Вы не предоставили прототип функции для printf, чтобы сообщить компилятору, что такое аргумент и типы возвращаемого значения. Обычно это делается, помещая строку #include <stdio.h> в начало программы.

John Bollinger 10.08.2018 15:25

Похоже, кто-то удалил мой комментарий. Не могу придумать почему и предлагаю рассказать мне в чате (или здесь). Я повторю то, что я сказал - здесь есть (или были) некоторые очень заблуждающиеся люди, утверждающие, что нотация ** относится к двумерному массиву - ЭТО НЕ. Имеется ввиду a pointer to a pointer и не более того. Этот второй указатель мог указывает на массив символов, как в argv, но может и не быть. Например, int **X объявляет X как указатель на указатель на int - обратите внимание, что здесь нет двух измерений.

Mawg says reinstate Monica 10.08.2018 21:55
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
17
824
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ваш код демонстрирует неопределенное поведение, потому что вы передаете 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] - символом?

Luka Kostic 10.08.2018 14:42

@LukaKostic В конце концов, char - это просто интегральный тип, целые числа и указатели взаимозаменяемы в c, но поведение такой сделки не всегда определяется. Более того, если бы адрес был тем, который находится в диапазоне памяти вашей программы, он все равно был бы недействительным, потому что он не указывает на реальную позицию в памяти, или это так? Это не было бы известно заранее, и поэтому это называется неопределенным поведением.

Iharob Al Asimi 10.08.2018 14:43

Ясно, что указатели и целые числа не являются взаимозаменяемый в C, но они являются interкабриолет. И некоторые компиляторы выполняют такие преобразования даже без преобразования, которое является расширением (хотя обычно они готовы выдать предупреждение об этом).

John Bollinger 10.08.2018 15:10

Я использую сервер 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])

Luka Kostic 10.08.2018 14:38

Да, именно так, если вам нужно прочитать char из строки (массива char), вы можете сделать это с помощью %c

Umair 10.08.2018 15:14

Другие вопросы по теме