Строковые литералы —последовательность символов, заключенная в двойные кавычки. В строковом литерале на один символ больше, чем используется при записи. Он всегда заканчивается нулевым символом '\0’.
Пример:
sizeof(“Бор”); // значение 4
Строковый литерал можно присвоить переменной типа char*
Но, изменение литерала через такой указатель является ошибкой.
Пример:
#include<stdio.h>
int main()
{
char cStr[]="Mars";
cStr[2]='p'; // ошибки нет
printf("cStr=%s\n",cStr);
char* pStr="Mars"; //
pStr[2]='p';// ошибка при выполнении программы
printf("pStr=%s\n",pStr);
return 0;
}
Объявление объектов и типов.
Все переменные в Си должны быть объявлены. Объявление происходит с помощью ключевого слова – спецификатора типа, идентификатора и модификаторов.
Модификатор | Определяемый тип |
* | указатель |
[] | массив |
() | функция |
Можно использовать одновременно более одного модификатора, что позволяет создавать множество сложных описателей типов.
Замечание: Некоторые комбинации недопустимы, например:
1. элементами массива не могут быть функции:
|
|
2. функции не могут возвращать функции.
При интерпретации сложных описателей квадратные и круглые скобки (справа от идентификатора) имеют приоритет перед звездочкой (слева от идентификатора).
Квадратные или круглые скобки имеют один и тот же приоритет и связываются слева направо.
Спецификатор типа рассматривается на последнем шаге, когда описатель уже полностью проинтерпретирован. Можно использовать круглые скобки, чтобы изменить порядок интерпретации.
Для интерпретации можно использовать простое правило: «изнутри наружу», состоящее из 4-х шагов.
1. Начать интерпретацию с идентификатора и посмотреть вправо, есть ли квадратные или круглые скобки.
2. Если они есть, то проинтерпретировать эту часть описателя и затем посмотреть налево в поисках звездочки.
3. Если на любой стадии справа встретится закрывающая круглая скобка, то вначале необходимо применить все эти правила внутри круглых скобок, а затем продолжить интерпретацию.
4. Интерпретировать спецификатор типа.
Пример:
int *(*comp[10])()
6 5 3 1 2 4
В примере объявляется переменная comp (1) как массив (2) из 10 указателей (3) на функции (4), возвращающие указатели (5) на целые значения(6).
/* Что напечатает программа? */
#include <stdio.h>
int main()
{
char note[]="You are welcome!";
char *ptr;
ptr=note;
puts(ptr); // You are welcome!
puts(++ptr; // ou are welcome!
note[7]='\0';
puts(note); // You are
puts(++ptr); // u are
return 0;
}
// Примеры объявления с использованием модификаторов
int board [8][8]; // массив массивов типа int
int **ptr; // указатель на указатель на тип int
int *risk[10]; // 10-элементный массив указателей на тип int
int (*wis)[10]; // указатель на 10-элементный массив типа int
|
|
int (*oop)[3][4]; // указатель на массив 3x4 типа int
char *fun(); // функция, возвращающая указатель на тип char
char (*fun)(); // указатель на функцию, возвращающую тип char
char (*fun())[3]; // функция, возвращающая указатель на 3-эл. массив har*/
Пример: /* Многоуровневые ссылки */
#include <stdio.h>
char *m[]={"January","February","March","April","May","June","July",
"August","September","October","November","December"};
char **mp[]={m+11,m+10,m+9,m+8,m+7,m+6,m+5,m+4,m+3,m+2,m+1,m};
char ***mpp[]={mp,mp+9,mp+6,mp+3};
char ****mppp=mpp;
int main()
{
int i;
printf("%s\n",***++mppp);
printf("%s\n",***--mppp);
for(i=0;i<12;i++)
printf("%s%c",mppp[0][0][i-11],(i==6)?'\n':' ');
printf("\n");
for(i=0;i<12;i++)
printf("%s%c",mppp[1][2][11-i],(i==5)?'\n':' ');
printf("\n");
printf("%s\n",*mppp[3][1]);
printf("%s\n",**mppp[1]+3);
printf("%s\n",mppp[2][-1][3]+2);
for(i=0;i<8;i++)
printf("%s\n",mppp[3][-2][-9]+i);
return 0;
}
Результаты выполнения программы:
March
December
January February March April May June July
August September October November December
December November October September August July
June May April March February January
August
ch
tober
February
ebruary
bruary
ruary
uary
ary
ry
y
Пример:
#include <stdio.h>
char *c[]={"TEST1 ","NOP ","FILE ","FIRST "};
char **cp[]={c+3,c+2,c+1,c};
char ***cpp=cp;
int main()
{
printf("%s ",**++cpp);
printf("%s ",*--*++cpp+3);
printf("%s",*cpp[-2]+3);
printf("%s\n",cpp[-1][-1]+1);
return 0;
}
Результаты выполнения программы:
FILE T1 STOP
Пример:/* нахождение определителя матрицы */
#include<stdio.h>
#include<windows.h>
#define n 4
void main()
{
float a[n][n],koef,det=1;
int i,j,k;
char cStr[]="Введите матрицу n на n";
CharToOem(cStr,cStr);
printf("%s\n",cStr);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%f",&a[i][j]);
// Прямой ход
for(i=0;i<n-1;i++){ // идем по строкам
for(j=i+1;j<n;j++){ //по соотв. столбцу
koef=a[j][i]/a[i][i];
for(k=i;k<n;k++) //по столбцам
a[j][k]-=a[i][k]*koef;}}
// Вывод результатов
for(i=0;i<n;i++){
for(j=0;j<n;j++)
printf("a[%d][%d]=%5.2f\t",i,j,a[i][j]);
printf("\n");}
for(i=0;i<n;i++)
det*=a[i][i];
printf("det=%5.2f\n",det);
}
Пример: /* решение СЛАУ методом Гаусса */
#include<stdio.h>
#include<windows.h>
#define n 4
void main()
{
float a[n][n+1],x[n],koef,det=1,y=0;
int i,j,k;
char cStr[]="Введите матрицу n на n+1";
CharToOem(cStr,cStr);
printf("%s\n",cStr);
for(i=0;i<n;i++)
for(j=0;j<n+1;j++)
scanf("%f",&a[i][j]);
// Прямой ход метода Гаусса
for(i=0;i<n;i++){ // идем по строкам
for(j=i+1;j<n;j++){ // по соотв. столбцу
koef=a[j][i]/a[i][i];
for(k=i;k<n+1;k++) // по столбцам
a[j][k]-=a[i][k]*koef;}}
// Вывод результатов
for(i=0;i<n;i++){
for(j=0;j<n+1;j++)
printf("a[%d][%d]=%5.2f\t",i,j,a[i][j]);
printf("\n");}
for(i=0;i<n;i++)
det*=a[i][i];
printf("det=%f\n",det);
// Обратный ход.
x[n-1]=a[n-1][n]/a[n-1][n-1];
for(i=n-2;i>=0;i--){
y=0;
for(j=n-1;j>i;j--)
y+=a[i][j]*x[j];
x[i]=(a[i][n]-y)/a[i][i];}
for(i=0;i<n;i++)
printf("x[%d]=%5.2f\n",i+1,x[i]);
}