Функции обработки строк в Cи

Язык Си / Функции обработки строк в Cи

 

В программе строки могут определяться следующим образом:

  • как строковые константы;
  • как массивы символов;
  • через указатель на символьный тип;
  • как массивы строк.

Кроме того, должно быть предусмотрено выделение памяти для хранения строки.

Любая последовательность символов, заключенная в двойные кавычки «», рассматривается как строковая константа.

Для корректного вывода любая строка должна заканчиваться нуль-символом '\0', целочисленное значение которого равно 0. При объявлении строковой константы нуль-символ добавляется к ней автоматически. Так, последовательность символов, представляющая собой строковую константу, будет размещена в оперативной памяти компьютера, включая нулевой байт.

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

Для помещения в строковую константу некоторых служебных символов используются символьные комбинации. Так, если необходимо включить в строку символ двойной кавычки, ему должен предшествовать символ «обратный слеш»: ‘\»‘.

Строковые константы размещаются в статической памяти. Начальный адрес последовательности символов в двойных кавычках трактуется как адрес строки. Строковые константы часто используются для осуществления диалога с пользователем в таких функциях, как printf().

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

 
char m[82];


Компилятор также может самостоятельно определить размер массива символов, если инициализация массива задана при объявлении строковой константой:
 
 
char m2[]="Горные вершины спят во тьме ночной.";
char m3[]={'Т','и','х','и','е',' ','д','о','л','и','н','ы',' ','п','о','л','н','ы',' ','с','в','е','ж','е','й',' ','м','г','л','о','й','\0'};

В этом случае имена m2 и m3 являются указателями на первые элементы массивов:

  • m2        эквивалентно &m2[0]
  • m2[0]     эквивалентно ‘Г’
  • m2[1]     эквивалентно ‘o’
  • m3        эквивалентно &m3[0]
  • m3[2]     эквивалентно ‘x’

 
При объявлении массива символов и инициализации его строковой константой можно явно указать размер массива, но указанный размер массива должен быть больше, чем размер инициализирующей строковой константы:

 
char m2[80]="Горные вершины спят во тьме ночной.";

Для задания строки можно использовать указатель на символьный тип.

 
char *m4;

В этом случае объявление массива переменной m4 может быть присвоен адрес массива:

 
 
 
m4 = m3;
*m4       эквивалентно m3[0]='Т'
*(m4+1)   эквивалентно m3[1]='и'

Здесь m3 является константой-указателем. Нельзя изменить m3, так как это означало бы изменение положения (адреса) массива в памяти, в отличие от m4.

Для указателя можно использовать операцию увеличения (перемещения на следующий символ):

 
m4++;

Массивы символьных строк

Иногда в программах возникает необходимость описание массива символьных строк. В этом случае можно использовать индекс строки для доступа к нескольким разным строкам.

 
 
char *poet[4] = {"Погиб поэт!", "- невольник чести -",
"Пал," , "оклеветанный молвой…"};


В этом случае poet является массивом, состоящим из четырех указателей на символьные строки. Каждая строка символов представляет собой символьный массив, поэтому имеется четыре указателя на массивы. Указатель poet[0] ссылается на первую строку:
*poet[0] эквивалентно 'П',
*poet[l] эквивалентно '-'.

Инициализация выполняется по правилам, определенным для массивов.
Тексты в кавычках эквивалентны инициализации каждой строки в массиве. Запятая разделяет соседние
последовательности.
Кроме того, можно явно задавать размер строк символов, используя описание, подобное такому:
 
char poet[4][23];


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

Массив строк

Свободный массив

Описание

 
сhar *poet[4];

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

Операции со строками

Большинство операций языка Си, имеющих дело со строками, работает с указателями. Для размещения в оперативной памяти строки символов необходимо:

  • выделить блок оперативной памяти под массив;
  • проинициализировать строку.

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

 
 
 
char *name;
name = (char*)malloc(10);
scanf("%9s", name);

Для ввода строки использована функция scanf(), причем введенная строка не может превышать 9 символов. Последний символ будет содержать '\0'.

Функции ввода строк

Для ввода строки может использоваться функция scanf(). Однако функция scanf() предназначена скорее для получения слова, а не строки. Если применять формат "%s" для ввода, строка вводится до (но не включая) следующего пустого символа, которым может быть пробел, табуляция или перевод строки.

Для ввода строки, включая пробелы, используется функция

 
char * gets(char *);

или её эквивалент
 
char * gets_s(char *);


В качестве аргумента функции передается указатель на строку, в которую осуществляется ввод. Функция просит пользователя ввести строку, которую она помещает в массив, пока пользователь не нажмет Enter.

Функции вывода строк

Для вывода строк можно воспользоваться рассмотренной ранее функцией

 
printf("%s", str); // str — указатель на строку

или в сокращенном формате

 
printf(str);


Для вывода строк также может использоваться функция
 
int puts (char *s);

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

Функция ввода символов

Для ввода символов может использоваться функция

 
char getchar();

которая возвращает значение символа, введенного с клавиатуры. Указанная функция использовалась в рассмотренных ранее примерах для задержки окна консоли после выполнения программы до нажатия клавиши.

Функция вывода символов

Для вывода символов может использоваться функция

 
char putchar(char);

которая возвращает значение выводимого символа и выводит на экран символ, переданный в качестве аргумента.

Пример Посчитать количество введенных символов во введенной строке.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
  char s[80], sym;
  int count, i;
  system("chcp 1251");
  system("cls");
  printf("Введите строку : ");
  gets_s(s);
  printf("Введите символ : ");
  sym = getchar();
  count = 0;
  for (i = 0; s[i] != '\0'; i++)
  {
    if (s[i] == sym)
      count++;
  }
  printf("В строке\n");
  puts(s);      // Вывод строки
  printf("символ ");
  putchar(sym); // Вывод символа
  printf(" встречается %d раз", count);
  getchar(); getchar();
  return 0;
}

Результат выполнения
Количество введенных символов в строке

Основные функции стандартной библиотеки string.h

Основные функции стандартной библиотеки string.h приведены в таблице.

Функция Описание
char *strcat(char *s1, char *s2)
присоединяет s2 к s1, возвращает s1
char *strncat(char *s1, char *s2, int n)
присоединяет не более n символов s2 к s1, завершает строку символом '\0', возвращает s1
char *strсpy(char *s1, char *s2)
копирует строку s2 в строку s1, включая '\0', возвращает s1
char *strncpy(char *s1, char *s2, int n)
копирует не более n символов строки s2 в строку s1, возвращает s1;
int strcmp(char *s1, char *s2)
сравнивает s1 и s2, возвращает значение 0, если строки эквивалентны
int strncmp(char *s1, char *s2, int n)
сравнивает не более n символов строк s1 и s2, возвращает значение 0, если начальные n символов строк эквивалентны
int strlen(char *s)
возвращает количество символов в строке s
char *strset(char *s, char c)
заполняет строку s символами, код которых равен значению c, возвращает указатель на строку s
char *strnset(char *s, char c, int n)
заменяет первые n символов строки s символами, код которых равен c, возвращает указатель на строку s

Пример использования функций

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
  char m1[80] = "Первая строка";
  char m2[80] = "Вторая строка";
  char m3[80];
  system("chcp 1251");
  system("cls");
  strncpy(m3, m1, 6);  // не добавляет '\0' в конце строки
  puts("Результат strncpy(m3, m1, 6)");
  puts(m3);
  strcpy(m3, m1);
  puts("Результат strcpy(m3, m1)");
  puts(m3);
  puts("Результат strcmp(m3, m1) равен");
  printf("%d", strcmp(m3, m1));
  strncat(m3, m2, 5);
  puts("Результат strncat(m3, m2, 5)");
  puts(m3);
  strcat(m3, m2);
  puts("Результат strcat(m3, m2)");
  puts(m3);
  puts("Количество символов в строке m1 равно  strlen(m1) : ");
  printf("%d\n", strlen(m1));
  _strnset(m3, 'f', 7);
  puts("Результат strnset(m3, 'f', 7)");
  puts(m3);
  _strset(m3, 'k');
  puts("Результат strnset(m3, 'k')");
  puts(m3);
  getchar();
  return 0;
}

Результат выполнения
Использование функций


Назад: Язык Си

Комментариев к записи: 44

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    #include <stdio.h>
    #include<stdlib.h>
    #include<time.h>


    int main() {
    unsigned int u,i,b=120,b1,b2,g1,g2,g=0;

    unsigned int pro[10];
    unsigned int pro2[45][2]={0};

    srand(time(NULL));
    for(i=0;i<10;i++)
    {
      pro[i]=rand()%100;
      printf("%d ",pro[i]);
    }
    printf("\r\n");

    for(u=0;u<9;u++)
    {
      for(i=u+1;i<10;i++)// в этом блоке все нормально...
      {

        pro2[g][0]= (pro[u]+pro[i]);
        pro2[g][1]=u;
        pro2[g][2]=i;
        printf("[%d][%d]%d ",pro2[g][1],pro2[g][2],pro2[g][0]);// для проверки работы
        g++;
      }
    }
    printf("\r\n g%d\r\n",g);//для проверки работы
    // 3 строки для проверки работы...
    // компилятор MinGW...
    printf("\r\n2\r\n");
      for(i=0;i<44;i++) { printf("[%d][%d] %d ",pro2[i][1], pro2[i][2], pro2[i][0]);}// здесь какая-то лажа происходит с колонкой pro2[][2] после цикла
    printf("\r\n\r\n");

    for(u=0;u<44;u++)
    {
      for(i=u;i<44;i++)
      {
        
        if(pro2[u][0]>pro2[i][0])
        {
          g=pro2[u][0];
          g1=pro2[u][1];
          g2=pro2[u][2];
          pro2[u][0]=pro2[i][0];
          pro2[u][1]=pro2[i][1];
          pro2[u][2]=pro2[i][2];
          pro2[i][0]=g;
          pro2[i][1]=g1;
          pro2[i][2]=g2;
          
        } 
             
      }
     printf("[%d][%d] %d ",pro2[i][1],pro2[i][2], pro2[i][0]);
    }

     printf("\r\n3 \r\n");
     

    for(i=1;i<44;i++)
    {
     //if(b=pro2[i][0]){printf("Ближайшее число %d",pro[i][0]);break;}
     if(b>pro2[i-1][0] && b<(pro2[i][0]) )
     {
       printf("\r\nзнач %d\r\n",pro2[i][0]);
       if((b-pro2[i-1][0])<(pro2[i][0]-b)){printf("ближайшее число %d+%d",pro[pro2[i-1][1]],pro[pro2[i-1][2]]);break;}
       else {printf("ближайшее число %d+%d",pro [pro2[i][1]], pro[pro2[i][2]]);break;}
     }
    }
      return 0;
    }
    не могу найти ошибку,в цикле записи все работает а после в целом столбце берутся неизвестно откуда какие-то данные...

    • Елена Вставская
      У Вас объявлен массив, в котором 2 колонки с индексами 0 и 1
      1
      unsigned int pro2[45][2]={0};
      А Вы пытаетесь обратиться к элементам третьей колонки: pro2[i][2]

  • Валерий
    У меня возникла сложность реализации функции strtok(). А точнее, хочу записать строку в массив строк(mas[4][35]). Слова должны разбиваться с использованием strtok() и записываться в массив построчно. Пробовал, но не получилось, не могу сообразить как нужно. Вывод на консоль происходит верно.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #include <stdio.h>
    #include <string.h>
    #define DELIM " "
    int main (void)
    {    
      int i = 0;
      char mas[4][35] = {""};
      char str [] = " test1  test2   test3  test4 ";
      char *istr;
      
      printf ("Begin string: [%s]\n", str);
      printf ("Result:\n");

      istr = strtok (str, DELIM);

      while (istr != NULL)
      {
        printf ("[%s]\n", istr);
    // fgets(mas[i], 35, stdin);
    // i++;
        istr = strtok (NULL, DELIM);
      }
    }

    • Елена Вставская
      Насколько я поняла, должно быть так:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      #include <stdio.h>
      #include <string.h>
      #define DELIM " "
      int main(void)
      {
        int i = 0;
        char mas[4][35] = { "" };
        char str[] = " test1 test2 test3 test4 ";
        char* istr;

        printf("Begin string: [%s]\n", str);
        printf("Result:\n");

        istr = strtok(str, DELIM);
        while (istr != NULL)
        {
          strcpy(mas[i], istr);
          i++;
          istr = strtok(NULL, DELIM);
        }
        for (int z = 0; z < i; z++)
        {
          printf("[%s]\n", mas[z]);
        }
      }

      • Валерий
        Все понял, спасибо. Всего то нужно было вместо fgets(), strcpy() делать. Но что то не догадался )))

  • Алексей
    Добрый день. У меня есть такая проблема. Мне нужно из файла считать в одну строку текст, состоящий из нескольких строк. Не подскажите, как это сделать ?

  • Владимир
    При выходе из функции указатель находится на последнем символе '\0'. Как его оптимально переместить на начало?

  • Здравствуйте. Подскажите, как можно обрабатывать строку в виде массива символов по их ASCII кодам? То есть как мне перевести 'a' в 97, а 97 в 'a'?

  • спасибо, как из массива взять сразу же несколько символов на пример; 1012 Мб тут надо взять только первые 4 символа буду рад и благодарен за помощь

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

  • Собко Виталий
    Подскажите пожалуста как сделать функцию, которая читает первые два слова из строки ввода в массив (это аргумент функции) и отвергает остальную часть строки. функция должна пропускать символы пробела. Определите слово как последовательность символов, не содержит символов пробела или табуляции.

    • Елена Вставская
      Считывать слово можно при помощи функции scanf("%s", word); или cin>>word. Остальные слова сами проигнорируются, если этот вызов повторить дважды

  • Здравствуйте, подскажите, как обрезать строку, отбросив все символы после точки.

    • Елена Вставская
      Перебрать в массиве все символы, пока не будет найдена точка. После точки в массив разместить 0 (конец строки)

  • Татьяна
    Пробую посимвольно записать ввод в строку. Почему-то на коротких строчках до 7 символов работает, а дальше начинает откусывать конец. Подскажите, пожалуйста, что не так?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    main()
    {
    int i=1;
    int c=0;
    char is[]=" ";
    c=getchar();
    while(c!='\n')
    {
         is[i]=c;
         c=getchar();
       i++;
     }
     printf("%d  %s", i, is);
     }

    • Елена Вставская
      Удивительно, что до 7 символов работает. Вроде после 2 символов должен перестать работать.
      1
      char is[]=" ";
      Для хранения строки выделяется всего 2 байта.
      1
      char is[100]={0};
      Будет работать до 100 символов.

      • Татьяна
        Теперь возникла другая проблема: в конце переменная i печатается, а строка is не печатается.
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        #include<stdio.h>
        main()
        {
        int i=1;
        int c=0;
        char is[100]={0};
        c=getchar();
        while(c!='\n')
        {
             is[i]=c;
             c=getchar();
             i++;
         }
         printf("%d  ", i);
         printf(" %s",  is);
         }


          • Александр
            int i = 0; По-вашему, строка начинается с символа конец строки.

          • Елена Вставская
            Нет, строка должна заканчиваться нулем.

  • Екатерина
    Здравствуйте, можете подсказать что я делаю неправильно? На этой строке "printf("%s", n[nomer].list);" останавливается. Выводятся не все строки текста.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    typedef struct node {
      char * data;
      char *list;
      int color;
    } NODE;

    int main()
    {
      FILE *in;
      char *ps, s[1000], *word, *name; 
      int nomer, list[20], i=0;
      in=fopen("dfs.txt","r"); // открыли файл для чтения
      NODE n[100];
        
      while (fgets(s,1000,in)!=NULL)
      {
        ps=s;
        word=strtok(ps," \n");
          printf("%s ",word);
        sscanf(word,"%d",&nomer);
        name=strtok(NULL," \n");
        n[nomer].data=malloc(strlen(name)+1);
        strcpy(n[nomer].data,name);
          printf("%s ",n[nomer].data);
        n[nomer].list=malloc(strlen((char*)list)+1);  
        while ((word=strtok(NULL," \n"))!=NULL)
        { // читать список
          sscanf(word,"%d",&list[i]);
          strcat(n[nomer].list, word);
          i++;
            }
            printf("%s", n[nomer].list);
            printf("\n");
            n[nomer].color=0;
        //printf("%s ",n[nomer].list);
      }
    }

  • Ангелина
    Здравствуйте, подскажите пожалуйста , как сделать сортировку строк по алфавиту



        • Елена Вставская
          Чтоб консоль не закрывалась сразу, а ждала нажатия любой кнопки


      • Здраствуйте обьясните как сделать сортировку слов по алфавиту пожалуйста, идею программы . Спасибо

        • Елена Вставская
          Слово представляет собой массив символов, привем коды букв идут по возрастанию: 'a'<'b' Поэтому открываем три цикла
          1
          2
          3
          4
          5
          6
          7
          8
          9
          for(int i=0;i<len-1; i++) // первое слово
            for(int j=i+1;j<len;j++) // второе слово
            {
              for(int k=0; s[i][k]!=0 && s[j][k]!=0; k++)
              {
                if(s[i][k]>s[j][k])
                  swap(s[i],s[j]); // меняем местами строки, функцию надо составить
              }
            }

  • Добрый вечер.Можете объяснить мне как я могу избавиться от пробела в сроках. Например, если у меня есть строка char name = "Hello world!", и чтобы мне вывело "Helloworld!" Большое спасибо за ответ!

    • Елена Вставская
      Убрать пробел в строке в тексте программы. А если строка заранее неизвестна, то
      1
      2
      3
      4
      5
      6
      7
      char res[80], s[80];
      cin.getline(s, 80); int j=0;
      for(int i=0; s[i]!=0; i++)
      if(s[i]!=&#039; &#039;)
        {res[j++]=s[i];}
      }
      res[j++]=0;

      • Николай
        извините руский язик не мой родной .Здраствуйте ,хочу через собсвеную функция считат сколко букви–символь слов имеет.хочу сделат по 2 начина разние .первий сделал второй не успел вот первийй
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        #include<unistd.h>
        #include<stdio.h>
        int myStrlen(char *s)/*char*s или char s[] е едно и също*/
        {
            int len = 0;
            while(*s != 0) {/*докато стигне терминиращ символ*/
                s++; /* *s е първия символ към който е насочен указателя -увеличава се със всяка итерация с 1*/
                len++;
                
            }
            printf("lethg is %d",len);/*отпечатваме дължината*/
            return len; /* функцията връща дължината*/
            
        }
        int main(){
            char*s="Nikolay";/*подаваме стринга*/
            myStrlen(s);/*викаме функцията*/
           sleep(4);/* 4 секунди пауза*/
            return 0;
        }
        второй начен не работает как надо
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        #include <stdio.h>
        #include<unistd.h>
        int myStrlen(char arr[]){
            int n;
            for(n=0;arr !='\0';arr++)
            n++;
            printf("lenthg is %d",n);
            return n;
        }
        int main(){
            char arr[]={'n','i','k'};
            myStrlen(arr);
            sleep(4);
            return 0;
        }
        здес ошибка

  • Добрый день!Помогите решить задачу, буду очень благодарна Дана строка, содержащая от 1 до 30 слов, в каждом из которых от 1 до 10 латинских букв и/или цифр; между соседними словами – не менее одного пробела, за последним словом – точка. Напечатать все слова, содержащие цифры, предварительно преобразовав каждое из них по следующему правилу: переписать слово задом наперед.

    • Елена Вставская
      Не занимаюсь решением учебных задач, поскольку сама являюсь преподавателем. Если есть вопросы - отвечу

  • Помогите плиз с задачей: Создать файл, содержащий произвольные текстовые строки. Подсчитать количество строк, начинающихся с буквы 'Я'. С первой частью проблем нет, а вот на второй пока встал.

    • Елена Вставская
      Работа с файлами описана здесь
      1
      2
      3
      4
      5
      6
      7
      char s[80];
      int count = 0;
      while(fin.getline(s,80))
      {
        if(s[0] == &#039;Я&#039;)
          count++;
      }
      & #039; - это апостроф :) Может, дойдут руки когда-нибудь исправить этот глюк.

  • Евгений
    Проверьте, пожалуйста, текст Вашей статьи - тут какая-то вакханалия с кавычками :)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *