Аргументы, переданные функции puts в C

Я только недавно начал изучать C. Я изучал концепцию массивов и указателей, когда наткнулся на камень преткновения в своем понимании этого.

Рассмотрим этот код -

#include<stdio.h>

int main()

 {

 char string[]="Hello";
 char *ptr;

 ptr=string;

 puts(*ptr);

 return(0);

 }

Он компилируется, но при выполнении возникает ошибка сегментации.

Предупреждение, которое я получаю:

введите ошибку в аргументе 1 для `puts'; найден 'char' ожидаемый 'указатель на char'

Теперь *ptr действительно возвращает символ «H», и мое первоначальное впечатление было, что он просто примет символ в качестве ввода.

Позже я понял, что puts() ожидает указатель на массив символов в качестве входных данных, но мой вопрос заключается в том, что когда я передаю что-то вроде этого - puts("H"), разве это не то же самое, что и puts(* ptr), учитывая, что *ptr содержит символ "H".


person user1720897    schedule 05.10.2012    source источник
comment
Предупреждение в значительной степени объясняет проблему. вы передаете один символ функции, которая ожидает указатель на символ.   -  person Richard Chambers    schedule 05.10.2012
comment
В C char — это не то же самое, что строка длины 1. Лучше думать о char как о небольшом числе.   -  person ams    schedule 05.10.2012


Ответы (6)


"H" — это строковый литерал, состоящий из 2 байтов 'H' и '\0'. Всякий раз, когда у вас есть «H» в вашем коде, имеется в виду указатель на область памяти с 2 байтами. *ptr просто возвращает одну переменную char.

person Maksim Skurydzin    schedule 05.10.2012

Выполняя puts(*str), вы разыменовываете переменную str. Затем это попытается использовать символ «H» в качестве адреса памяти (поскольку на это указывает str), а затем segfault, поскольку это будет недопустимый указатель (поскольку он, вероятно, выйдет за пределы памяти вашего процесса). Это связано с тем, что функция puts принимает указатель в качестве аргумента.

То, что вы действительно хотите, это puts(str).

Кстати, последний пример puts("h") заполняет таблицу строк "h" во время компиляции и заменяет определение там неявным указателем.

person slugonamission    schedule 05.10.2012
comment
Как вы пришли к мысли, что если взять адрес «H», он попадет в область памяти вашего BIOS? В этом ответе есть некоторая путаница (и нет, предоставление строкового литерала - это не расширение, а обычный C). - person DevSolar; 05.10.2012
comment
@slugonamission: Кроме того, DevSolar прав, вы просто предполагаете, что он попадет в область памяти вашего BIOS. На самом деле это неправильно, и я бы удалил это на вашем месте. :) - person netcoder; 05.10.2012
comment
@netcoder - это произошло из-за того, что разыменовав str, вы получите значение, на которое оно указывает, в данном случае 'H', а точнее, 0x48, которое, я думаю, оно всегда сопоставляло с вашим Память БИОСа. - person slugonamission; 05.10.2012
comment
По крайней мере на х86. Конечно, это неправильно практически на любой другой платформе, поэтому я удалил и это: P - person slugonamission; 05.10.2012
comment
Спасибо за разговор о таблице строк и неявном указателе. Я был сбит с толку, почему в puts(H) H означает указатель на массив символов. Также теперь имеет смысл ошибка сегментации. - person user1720897; 05.10.2012
comment
Это все еще неправильно. «H» — это просто целочисленное значение, находящееся в разделе данных вашего двоичного файла. - person DevSolar; 06.10.2012
comment
да. Разыменование возвращает «H». Затем этот «H» неявно преобразуется в указатель, поскольку puts требует аргумента char*, следовательно, попытка чтения с адреса 0x48. - person slugonamission; 06.10.2012

Функция puts() принимает указатель на строку, а вы указываете один символ.

Взгляните на этот Урок 9: Строки C.

Поэтому вместо того, чтобы делать

#include<stdio.h>

int main()

 {

 char string[]="Hello";
 char *ptr;

 ptr=string;    // store address of first character of the char array into char pointer variable ptr
                // ptr=string is same as ptr=&string[0] since string is an array and an
                // array variable name is treated like a constant pointer to the first
                // element of the array in C.
 puts(*ptr);    // get character pointed to by pointer ptr and pass to function puts
                // *ptr is the same as ptr[0] or string[0] since ptr = &string[0].
 return(0);

 }

Вместо этого вы должны делать

#include<stdio.h>

int main()

 {

 char string[]="Hello";
 char *ptr;

 ptr=string;  // store address of first character of the char array into char pointer variable ptr

 puts(ptr);  // pass pointer to the string rather than first character of string.

 return(0);

 }
person Richard Chambers    schedule 05.10.2012

Когда вы вводите строку в get или хотите отобразить ее с помощью puts, вам нужно было фактически передать местоположение указателя или строки.

Например

char name[] = "Something";

если вы хотите напечатать это

вы должны написать printf("%s",name); --> name actually stores the address of the string "something"

и с помощью puts, если вы хотите отобразить

puts(name) ----> same as here address is put in the arguments
person Jamal Hussain    schedule 05.10.2012

No.

'H' - символьный литерал.

Фактически «H» представляет собой массив символов с двумя элементами: «H» и завершающий нулевой байт «\0».

person DevSolar    schedule 05.10.2012

puts ожидает ввода указателя на строку, поэтому он ожидает адрес памяти. но в вашем примере вы предоставили содержимое памяти, которое равно *ptr. *ptr - это содержимое памяти с адресом ptr, который равен h

ptr это адрес памяти

*ptr это содержимое этой памяти

входным параметром puts является тип адреса, но вы указали тип char (содержимое адреса)

puts запускает печать символ за символом, начиная с адреса, который вы вводите в качестве ввода, до памяти, содержащей 0, а затем прекращает печать

person MOHAMED    schedule 05.10.2012