2016-08-10 3 views
-6
#include<stdio.h> 

int strlen1(char *s){ 

    char *p=s; 
    printf("%s\n",s); 

    printf("size of s=%d\n",sizeof(s)); 

    while(*p!='\0') 

    p++; 

    return p-s; 

} 

int main(){ 

    int len; 
    char c[]="welcome back "; 
    len=strlen1(c); 
    printf("%d",len); 
    return 0; 

} 

В этом коде массив символов передается как параметр функции strlen(), в котором s является указателем (адрес первого элемента массива c), а затем почему он печатает весь массив, а его размер равен только 8.And присвоение указателя char p как s не будет ссылаться на его адрес, а на его значение. Пожалуйста, очистите мои концепции и основы всего этого кода. Спасибо заранее.Символьный массив в аргументе функции как указатель или массив?

+2

В С «строка» представляет собой массив 'char's, по меньшей мере, один элемент равен '0'. – alk

+0

Он печатает размер 8, потому что это размер указателя 'char *' в вашей системе. Кроме того, спецификатор формата '% d' ожидает аргумент типа' int', но ваш аргумент 'sizeof (s)' имеет тип 'size_t'. Вы можете исправить это, переведя аргумент в ожидаемый тип: '(int) sizeof (s)'. –

+0

Возможный дубликат [Размер массива на языке программирования C] (http://stackoverflow.com/questions/1975128/sizeof-an-array-in-the-c-programming-language) –

ответ

2

назначая обугленного указатель р как s не будет ссылаться на свой адрес, а его значение

При назначении с до р вы на самом деле присвоения адреса.
Если вы хотите присвоить только значение, то вам нужно будет сделать что-то вроде этого:

char p; //create a char called p 
p = *s; //value at p = value at s 

Но тогда вы не можете сканировать через массив в цикле при использовании р.


почему он печатает весь массив

% S означает держать печать до тех пор, пока не увидите пустой символ. Так как p указывает на первый адрес вашей строки, он печатает все это.


его размер составляет всего 8

SizeOf (ы) означает, что размер переменной х. Вы определили s как указатель на char, поэтому он возвращает размер или указатель на char (8). Функция вы хотите:

strlen(s); 

EDIT: Фиксированный первый пример, чтобы удалить неопределенное поведение.

+0

'strlen()' дает вы длина строки, которая (надеюсь, ;-)) отличается от размера массива, который может быть сохранен. – alk

+2

'char * p; * p = ... 'это вызывает неопределенное поведение, поскольку' p' указывает «нет где» и де-ссылку. – alk

0

% s принимает адрес памяти и печатает символы до тех пор, пока не найдет нулевой символ.

Когда u инициализирует указатель во время объявления, как в этом случае «char * p = s;» , адрес s присваивается p, а не значение.

  1. char * p; p = s;

  2. char * p = s;

Оба - то же самое.

0

В большинстве случаев выражение типа «N-элемента массива T» будут преобразованы («распад») к выражению типа «указатель на T», а значение выражения будет адрес первого элемента массива.

Исключения из этого правила являются:

  • когда выражение массива операнд из sizeof или одинарных & операторов;
  • , когда выражение массива является строка символов используются для инициализации другого массива в объявлении (таким образом, "welcome back " строки символов, используемом для инициализации c является не преобразуется в выражение указателя, вместо этого, содержимых строк буквальных копируются до c).

Когда вы звоните

len=strlen1(c); 

выраженияc преобразуются из типа «14-элементный массив char» в «указатель на char», и это выражение указателя является то, что на самом деле получает передаются strlen1.

В контексте объявления параметра функции T a[N] и T a[] обрабатываются так же, как T *a; a объявлен как указатель на T, а не на массив T. Это имеет смысл, поскольку функция не может получать выражение массива в качестве параметра; он будет преобразован в указатель перед передачей функции.

, то почему он печатает весь массив

Вот как работает спецификатор %s преобразования; он сообщает printf, чтобы начать печатать последовательность символов, начиная с адреса, указанного s, пока не увидит 0-значный байт.

его размер составляет всего 8

Типом выраженияs является char *, так sizeof s эквивалентно sizeof (char *) (то есть, размер указателя char), так, что вам 're display - количество байтов, необходимых для хранения указателя , а не размера строки, на которую указывает s.

Вот карта памяти о том, как вещи играть на моей платформе, которая может помочь понять некоторые из этих понятий:

  Item  Address 00 01 02 03 
      ----  ------- -- -- -- -- 
"welcome back "  0x400c89 77 65 6c 63 welc 
         0x400c8d 6f 6d 65 20 ome. 
         0x400c91 62 61 63 6b back 
         0x400c95 20 00 25 64 ..%d 

       c 0x7fffa9c401a0 77 65 6c 63 welc 
       0x7fffa9c401a4 6f 6d 65 20 ome. 
       0x7fffa9c401a8 62 61 63 6b back 
       0x7fffa9c401ac 20 00 00 00 .... 

      len 0x7fffa9c401bc 00 00 00 00 .... 

       s 0x7fffa9c400e8 a0 01 c4 a9 .... 
       0x7fffa9c400ec ff 7f 00 00 .... 

       p 0x7fffa9c40128 a0 01 c4 a9 .... 
       0x7fffa9c4012c ff 7f 00 00 .... 

Это положение вещей на входе в strlen1.

Сохраняется строковый литерал "welcome back ", начинающийся по адресу 0x400c89. Массив символов c сохраняется с адреса 0x7fffa9c401a0.Объект-указатель s хранится начиная с адреса 0x7fffa9c400e8 и содержит адрес объекта объекта массива c (x86 является малоподобным, поэтому он читает от младшего байта до наиболее значимого байта). Объект s составляет всего 8 байтов, поэтому вы получили 8 в качестве вывода для sizeof(s).

Нельзя использовать спецификатор формата %d для печати значения типа size_t (это то, что возвращает sizeof). Если вы используете C99 или более позднюю версию, используйте %zu; если вы используете C89, используйте %lu и привести значение к unsigned long:

printf("size of s=%zu\n", sizeof s); // C99 or later 
printf("size of s=%lu\n", (unsigned long) sizeof s); /* C89 */ 
+0

Спасибо. Это описание действительно полезно. – anshika24