2016-07-28 2 views
3
#include <stdio.h> 

    int main() 
    { 
     char str[3][15] = {"Pointer to","char","program"}; 
     char (*pt)[15] = str; // statement A 
     char *p = (char *)str; // statement B 
     printf("%s\n",p[3]); // statement C - Seg Fault in this line 
     printf("%s\n",p); // working properly displaying "Pointer to" 
     printf("%s\n",p+1); // here it is pointing to second element of first array so displaying "ointer to" 
     printf("%s\n",pt+1); // printing properly "char" as expected 
     int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 
     int (*nm)[3] = num[1]; 
     int *n = num; 
     printf("n - %d\n",n[10]); // statement D 
     printf("nm - %d\n",nm[0][0]); 
     return 0; 
    } 

Мои вопросы:В чем разница между указателем на 2D-массив и указателем на 2D-массив?

  1. Пожалуйста, помогите мне, чтобы получить четкое представление о данных, хранящих механизм в случае массив символов и целочисленный массив

  2. В приведенной выше программе я понять, что, когда указатель для массива char указывается на двумерный массив символов, как показано в инструкции A, отображается , отображая его правильно, но когда он указывается нормальным указателем char и пытается распечатать символ в выражении C, он получает Se gFault, вместо этого он должен печатать 'n' (символ третьего числа в первом массиве «Pointer to»), так что с путаницей, почему в случае массива int я получаю надлежащее значение элемент n = 11 в инструкции D и почему в этом случае (оператор C) неправильно печатается.

  3. Как данные будут храниться в случае массив символов он будет сохранен в этой форме, показанной ниже


char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o'}, 
        {'c','h','a','r'}, 
        {'p','r','o','g','r','a','m'}}; 

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

+0

'char str [3] [15] = {{'P', 'o', 'i', 'n', 't', 'e', ​​'r', '', 't', ' 'o', '\ 0'}, {'c', 'h', 'a', 'r', '\ 0'}, {'p', 'r', 'o', 'g ',' r ',' a ',' m ',' \ 0 '}}; ' – LPs

+0

оператор D работает, потому что' num' получает выделение в виде единого массива, который компилятор обращается по следующей формуле: с учетом выражения ' num [row] [col] ', то это то же самое, что' * ((int *) num + row * 4 + col) '. – miravalls

+0

'printf ("% s \ n ", p [3]);' -> 'printf ("% s \ n ", &p[3]);' – LPs

ответ

2

Ваш segfault вызван тем, что вы передаете неправильный тип printf.

Запись p[3] вы deferencing указатель на 4 char первой строки матрицы str. То же, что *(p+3)

Если вы хотите напечатать 3-й символ вы должны

printf("%c\n",p[3]); 

Если вы хотите, чтобы напечатать первый C-String (строка 0 матрицы) вы должны:

printf("%s\n",&p[3]); 

потому что %s хочет char *.

Если добавить, по крайней мере для GCC, -Wall вариант вашей команды, компилятор покажет вам хорошее и полезное предупреждение:

test.c:8:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=] 
     printf("%s\n",p[3]); // statement C - Seg Fault in this line 

О вопросе 3 Вы должны принять к сведению, что правильное хранение является:

char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o','\0'}, 
        {'c','h','a','r','\0'}, 
        {'p','r','o','g','r','a','m','\0'}}; 

из-за того, что C-строки являются нуль прекращается, так, например, строка "Pointer to" будет занимать 11 символов


Последнее, что касается указателя int.Он хорошо работает из-за %d. Спецификатор формата имеет значение int, а не адрес. Так писать:

printf("n - %d\n",n[10]); 

полностью правильно, потому что n[10] является разыменованием 11-элемента num матрицы, что означает, что 3-й элемент 3-го ряда. То же, что и *(n+10)

+0

* Написание p [3] вы откладываете указатель на третий символ * Это неверно. – 2501

+0

Использование 'p' для выделения из границ внутреннего массива, такого как' p [10] ', является неопределенным поведением. – 2501

+0

@ 2501 Хорошо для первого комментария, я отредактировал, но я не понимаю вас во втором. – LPs

3

Посмотрите на свой код шаг за шагом.

char str[3][15] = {"Pointer to","char","program"}; 

Здесь вы создали массив из трех массивов пятнадцати char лет. И вы инициализируете каждый из массивов char строк со строковыми литералами. Если литералы короче, чем массив - последние элементы заполняются нулями, так же, как:

char str[3][15] = { 
    {'P', 'o', 'i', 'n', 't', 'e', 'r', ' ', 't', 'o', 0, 0, 0, 0, 0}, 
    {'c', 'h', 'a', 'r', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 
    {'p', 'r', 'o', 'g', 'r', 'a', 'm', 0, 0, 0, 0, 0, 0, 0, 0} 
}; 

Тогда

char (*pt)[15] = str; // statement A 

Здесь вы создаете pt как указатель на массив из пятнадцати char-х , и вы инициализируете его с адресом str[0], то есть pt указывает на первый char[15] массив от str.

Следующая

char *p = (char *)str; // statement B 

Это не в порядке. Насколько я вижу, вы пытаетесь сделать p, чтобы указать на первое char в памяти, которое занимает str. Выражение str имеет тип char (*)[15], то есть это указатель на массив символов, а не указатель на char (и из-за этого вы вынуждены использовать литье), и независимо от того, что str действительно указывает на ячейку, где хранится 'P' - вы должны к нему более, как типобезопасному:

char *p = &str[0][0]; // the same as "p = str[0];" 

str[0] ссылается на первый элемент str, т.е. типа str[0] представляет собой массив из пятнадцати char-х, то вы можете просто обратиться к первому char и возьмите его адрес - &(str[0])[0], или просто используйте тот факт, что выражение с типом «array» распадается на тип «указатель t o элемент первого массива ", поэтому работает str[0].

Давайте идти вперед

printf("%s\n",p[3]); // statement C - Seg Fault in this line 

Эта строка вызывает неопределенное поведение, так как спецификатор формата требуется второй аргумент, чтобы быть const char *, но вы передаете char. Если вы хотите напечатать один символ - это сделать:

printf("%c\n", p[3]); // prints "n" 

Тогда

printf("%s\n",p); // working properly displaying "Pointer to" 
    printf("%s\n",p+1); // here it is pointing to second element of first array so displaying "ointer to" 

Они работают хорошо, потому что тип второго аргумента является правильным, и мы знаем, что строки завершающий ноль.

printf("%s\n",pt+1); // printing properly "char" as expected 

Говоря откровенно - это неверно, так как pt + 1 является «указатель на массив char», но вы должны передать «указатель на символ». Оно должно быть переписано в виде:

printf("%s\n",*(pt+1)); // or pt[1] 

Но это, кажется, работает, потому что независимо от типа несовместимости оба указателя указывают на то же место.

Следующий раздел о int.

int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 
int (*nm)[3] = num[1]; 
int *n = num; 

Вот две ошибки: nm не должен быть инициализирован с num[1], так как они имеют несовместимые типы: «указатель на массив из трех int» против «массива из четырех int/указателя на int» (благодаря убывающему). И n не могут быть инициализированы num, потому что они тоже несовместимы. По моей догадке о том, что вы хотите, это должно выглядеть в следующем виде:

int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 
int (*nm)[4] = num + 1; 
int *n = &num[0][0]; 

И последние из них:

printf("n - %d\n",n[10]); // statement D 
printf("nm - %d\n",nm[0][0]); 

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

Надеюсь, я затронул все ваши вопросы.

+0

Отличный ответ .... – 2501

+0

Отлично. лучше, чем моя. ;) – LPs

Смежные вопросы