Стрингови (1)

У програмском језику C постоје само нумерички типови података, а један од њих, тип char, користи се за представљање појединачних карактера.

За манипулацију текстом користе се низови елемената типа char, где се иза последњег елемента додаје NULL карактер ‘\0’ (празан карактер, завршни карактер). Низ сачињен од карактера (знакова) назива се стринг или ниска.

Подсетите се да се у програмском језику C користи ASCII кôд. У табели испод јасно се види које нумеричке вредности имају одређени карактери. Нпр. карактер A има декадну вредност 65, карактер 9 има декадну вредност 57, карактер ? има декадну вредност 63 итд.

ascii_table

Бројчана вредност NULL карактера износи нула. Треба водити рачуна да цифра нула у ASCII табели има вредност 48, те да цифра нула није исто што и NULL карактер.

Стрингови се могу обрађивати као остали низови. Појединачним елементима стринга може се приступити помоћу индекса или помоћу показивача, а крај низа препознаје се по NULL карактеру.

На пример, ако се декларише следећи стринг:

char s[10];

важи да први елемент има индекс 0, а последњи индекс 9, као и да се у њему може чувати само девет карактера, јер последњи десети карактер треба бити NULL карактер.

 

Иницијализација стрингова

Стрингове можемо иницијализовати на више начина. На пример:

char s1[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
char s2[] = {'H', 'e', 'l', 'l', 'o', '\0'};
char s3[6] = "Hello";
char s4[] = "Hello";

У овом примеру декларисали смо и иницијализовали четири стринга дужине шест у којима се чува по пет карактера. У стринговима s3[] и s4[] NULL карактер аутоматски се уписује од стране C компајлера.

 

Иницијализација дводимензионалних стрингова

У програмском језику C могу се користити и дводимензионални стрингови односно дводимензионални низови (матрице) карактера. На пример:

char s5[6][9] = {"Hello", "world!", "My", "name", "is", "Velimir."};

Прва димензија може се изоставити:

char s5[][9] = {"Hello", "world!", "My", "name", "is", "Velimir."};

док следеће иницијализације нису валидне:

char s5[6][] = {"Hello", "world!", "My", "name", "is", "Velimir."};
char s5[][] = {"Hello", "world!", "My", "name", "is", "Velimir."};

У овом примеру декларисали смо и иницијализовали дводимензионални стринг (матрицу карактера) s5 који има димензије 6х9:

      1   2   3   4   5   6   7   8   9
   +-----------------------------------------
1  |  H   e   l   l   o   \0  \0  \0  \0
2  |  w   o   r   l   d   !   \0  \0  \0
3  |  M   y   \0  \0  \0  \0  \0  \0  \0
4  |  n   a   m   e   \0  \0  \0  \0  \0
5  |  i   s   \0  \0  \0  \0  \0  \0  \0
6  |  V   e   l   i   m   i   r   .   \0
   |

 

ЗАДАТАК 1. (задатак 41. из Приручника) У програмском језику Ц је дата декларација променљивих, а касније у коду извршен позив функције на следећи начин:

int k, i;
char lista[10][50], ime[50];

if( Formiraj(lista[i], ime, k) == NULL) { ... }

На основу позива, проценити каквог је облика прототип функције.

  1. void *Formiraj(char s1, char s2, int x);
  2. char Formiraj(char *s1, char *s2, int x);
  3. int *Formiraj(char s1[], char s2[], int x);
  4. int Formiraj(char s1[], char s2[], int x);
  5. char *Formiraj(char s1, char s2, int x);

 

ЗАДАТАК 2. (задатак 108. из Приручника) У програмском језику Ц дата је декларација показивачке променљиве:

char *imena[3]={"Petar", "Misa", "Slavko"};

На слици 1. приказан је садржај зоне у меморији где су смештени стрингови један иза другог, као и адресе на које је смештен сваки карактер. На слици 2. приказан је дефинисан низ imena[] који садржи адресе меморисаних стрингова. Одредити садржај елемената низа imena[] и на линију поред дописати одговарајућу адресу.

Слика 1.

P   e   t   a   r   \0  M   i   s   a   \0  S   l   a   v   k   o   \0
0   1   2   3   4   5   6   7   8   9   А   B   C   D   E   F   10  11

Слика 2.

imena[0]  Petar    0
imena[1]  Misa     6 
imena[2]  Slavko   B

 

Читање и писање карактера

Функције printf() и scanf()

За испис карактера из стринга и упис карактера у стринг могу се користити стандардне библиотечке функције printf() и scanf() помоћу конверзије %s. И за испис и за упис, одговарајући аргумент функције треба да буде стринг или показичач на први елемент стринга из кога се исписује, односно, у кога се уписује текст. Пошто је име стринга уједно и адреса првог елемента стринга, нема потребе наводити оператор &.

Код исписа, исписују се сви карактери до NULL карактера укључујући и размаке (SPACE карактере) и карактере за прелазак у нови ред.

 

ЗАДАТАК 3. (задатак 144. из Приручника) Са десне странe дате су врсте конверзије, а са леве типови података који се користе у функцији за приказ података printf() у програмском језику Ц. На линију испред типа конверзије унети број којим је означен одговарајући тип података.

  1. char    3  %f
  2. sting   2  %s
  3. float   3  %g
  4. double  4  %lf
  5. long    3  %e
  6. short   1  %c

 

ЗАДАТАК 4. Написати програм који исписује два стринга на стандардни излаз помоћу функције printf(). Елементи стрингова могу бити и размаци и карактери за прелаза у нови ред.

#include <stdio.h>
int main(void)
{
    char ime[] = "Velimir";
    char poruka[] = "\nHave a nice day!";
    printf("Hello %s. %s", ime, poruka);
}

Извршавањем овог програма исписаће се порука:

Hello Velimir.
Have a nice day!

 

ЗАДАТАК 5. (задатак 23. из Приручника) Дат је део кода програма написаног у програмском језику Ц. Одредити шта ће се исписати на екрану након његовог извршавања.

char s[20]={'A','c','a',' ','j','e','\0','d','o','b','a','r'};
char t[12]={'A','c','a',' ','j','e','\0','d','o','b','a','r'};
char *poc=s+7;
printf("\nString = %s\n",poc);
printf("String = %s\n",s+4);
printf("Znak = %c\n",*poc);
printf("String = %s\n",t+7);

1.

String = Aca je dobar
String = Aca
Znak = A
Aca je dobar

2.

String = Acа
String = je
Znak = d
Neće prikazati ništa

3.

String = dobar
String = je
Znak = d
Nepredvidivo jer string t ima 12 znakova koliko i
rezervisani prostor, a poslednji znak nije \0'

4.

String = dobar
String = dobar
Znak = d
Nepredvidivo jer string t ima 12 znakova koliko i
rezervisani prostor, a poslednji znak nije \0'

 

Код уписа у стринг помоћу функције scanf(), прескачу се размаци и читају карактери до првог следећег размака, па се додаје NULL карактер.

 

ЗАДАТАК 6. Измени програм из четвртог задатка тако да се први стринг учитава са стандардног улаза.

#include <stdio.h>
int main(void)
{
    char ime[20];
    char poruka[] = "\nHave a nice day!";
    scanf("%s", ime);
    printf("Hello %s. %s", ime, poruka);
}

Након извршавања овог програма и уноса имена Velimir добиће се исти резултат као и у претходном примеру.

Velimir
Hello Velimir.
Have a nice day!

Чак иако се унесе Velimir Radlovacki резултат ће бити исти, јер су исписују унети карактери само до првог размака!

Velimir Radlovacki
Hello Velimir.
Have a nice day!

 

Поред функција printf() и scanf() које користе сложене конверзије за испис/упис, постоје и функције које се користе искључиво за рад са карактерима. Свака од њих врши само једну радњу, али је врши много брже и ефикасније од printf() и scanf() функција.

 

Функције putchar()

Исписује карактер преко стандардног излаза. Вредност функције је кôд исписаног карактера или EOF ако се десила грешка приликом исписа. Тип параметра је int.

int putchar ( int char );

 

ЗАДАТАК 7. Написати програм који исписује један карактер на екрану помоћу функције putchar().

#include <stdio.h>
int main(void)
{
    char c = 'V';
    putchar(c);
}

 

Функције getchar()

Учитава карактер преко стандардног улаза, где карактер може били и размак. Вредност функције је кôд прочитаног карактера или EOF (end of file) ако је прочитан сигнал за крај датотеке CTRL+Z, или ако се десила грешка у читању.

int getchar ( void );

 

ЗАДАТАК 8. Написати програм који учитава карактер са стандардног улаза помоћу функције getchar() па након тога исписује његов кôд.

#include <stdio.h>
int main(void)
{
    int c;
    c = getchar();
    printf("Kod unetog karaktera je: %d", c);
}

 

ЗАДАТАК 9: Напишите програм који учитава текст са стандардног улаза помоћу функције getchar() све док се не притисне CRTL+Z, потом претвара сва унета мала слова у тексту у велика и исписује резултат на стандардни излаз помоћу функције putchar().

#include <stdio.h>
int main(void)
{
    int c;
    while ((c = getchar()) != EOF)
        if ('a' <= c && c <= 'z')
            putchar(c - 32);
        else
            if (c == '\n')
                putchar('\n');
            else
                putchar(c);
}

У датом решењу искористили смо својство из ASCII табеле, у којој се види да је резултат одузимања декадних вредности великих слова и одговарајућих малих слова увек -32 тј. A – a = 65 – 97 = -32, B – b = 66 – 98 = -32 итд.). Тест пример:

Velimir Radlovacki
VELIMIR RADLOVACKI

 

Функција gets()

Учитава карактере са стандардног улаза у стринг све до карактера за прелазак у нови ред ‘\n’ или до EOF и на крај стринга додаје карактер NULL. Вредност функције једнака је адреси првог елемента стринга, а у случају грешке приликом читања једнака је вредности NULL.

char * gets ( char * str );

 

ЗАДАТАК 10: Напишите програм који учитава текст у стринг помоћу функције gets() и исписује унети текст на стандардни излаз.

#include <stdio.h>
int main(void)
{
    char s[50];
    printf ("Unesite ime i prezime: ");
    gets(s);
    printf("Uneli ste: %s", s);
}

Након извршавања овог програма и уноса имена Velimir Radlovacki, унети ред текста ископираће се у стринг s на чијем ће крају бити додат NULL карактер.

Unesite ime i prezime: Velimir Radlovacki
Uneli ste: Velimir Radlovacki

 

Функција puts()

Исписује текст на главни излаз из стринга до NULL карактера, примењујући карактер за прелазак у нови ред на крају. Вредност функције у случају грешке је EOF, а иначе је не-негативан број.

int puts ( const char * str );

 

ЗАДАТАК 11: Напишите програм који исписује садржај стринга на главни излаз помоћу функције puts().

#include <stdio.h>
int main(void)
{
    char s[] = "Velimir Radlovacki";
    puts(s);
}

Након извршавања овог програма исписаће се текст из стринга s на главни излаз и курсор ће прећи у нови ред:

Velimir Radlovacki

 

ЗАДАТАК 12. Напишите програм који са стандардног улаза учитава текст у стринг, избацује све размаке (SPACE карактере) из стринга, па након тога исписује садржај стринга на стандардни излаз.

#include <stdio.h>
int main(void)
{
    char s[80];
    int i, j;
    gets(s);
    for(i = 0, j = 0; s[i] != '\0'; i++)
        if (s[i] != ' ')
            s[j++] = s[i];
    s[j] = '\0';
    puts(s);
}

Након извршавања овог програма, ако унесемо било који текст, исти текст ће се исписати без рамака.

Ja sam ucenik drugog razreda.
Jasamucenikdrugograzreda.

 

Функције за класификацију и конверзију карактера

У заглављу ctype.h налази се група библиотечких функција за класификацију карактера:

isalnum() – проверава да ли карактер афланумерички карактер.
isalpha() – проверава да ли карактер слово.
islower() – проверава да ли карактер мало слово.
isupper() – проверава да ли карактер велико слово.
isdigit() – проверава да ли карактер декадна цифра.
isxdigit() – проверава да ли карактер хексадекадна цифра.
isspace() – проверава да ли карактер празнина (SPACE карактер).
isgraph() – проверава да ли карактер штампајући, а није размак.
isprint() – проверава да ли карактер штампајући, укључујући и размак.
ispunct() – проверава да ли карактер знак, а није слово или цифра.
iscntrl() – проверава да ли карактер управљачки карактер.

Ове функције као параметар узимају кôд карактера (int) и враћају int који може бити или нула (логичка неистина), или вредност различита од нуле (логичка истина).

У истом заглављу постоје и функције за конверзију, које као параметар узимају кôд карактера (int) и враћају int који представља кôд резултујућег карактера.

tolower() – конвертује слово у мало слово.
toupper() – конвертује слово у велико слово.

 

ЗАДАТАК 13. Решите девети задатак користећи и функције из заглавља ctype.h.

#include <stdio.h>
#include <ctype.h>
int main(void)
{
    int c;
    while ((c = getchar()) != EOF)
        if (islower(c))
            putchar(toupper(c));
        else
            if (c == '\n')
                putchar('\n');
            else
                putchar(c);
}

 

ЗАДАТАК 14. Напишите програм који пребројава колико има речи у унетом тексту. Реч се може дефинисати као континуални низ слова који не садржи размак.

#include <stdio.h>
#include <ctype.h>
int nadjiRec(void)
{
    int c;
    while(isspace(c = getchar()));
    if (c != EOF)
    {
        while((c = getchar()) != EOF && !isspace(c));
        return 1;
    }
    return 0;
}
int main(void)
{
    int n = 0;
    while(nadjiRec() == 1)
        ++n;
    printf("Uneti broj reci je %d", n);
}

Тест пример:

Ko jos danas broji reci
^Z
Uneti broj reci je 5

 

ЗАДАТАК 15. Напишите функцију која одређује број цифара у унетом стрингу s[] и програм који је користи.

#include <stdio.h>
#include <ctype.h>
int brCifara(char s[])
{
    int i, n = 0;
    for(i = 0; s[i] != '\0'; i++)
        if(isdigit(s[i]) != 0)
            n++;
    return n;
}
int main(void)
{
    char s[80];
    gets(s);
    printf("Broj cifara u unetom stringu je: %d", brCifara(s));
}

Тест пример:

Danas je 20.02.2020.
Broj cifara u unetom stringu je: 8

 

Функције за обраду стрингова

У заглављу string.h налазе се функције за обраду стрингова. Неке од често коришћених су:

strcpy(s1, s2) – копира стринг s2 у стринг s1 (заједно са NULL карактером). На пример:

#include <stdio.h>
#include <string.h>
int main(void)
{
	char s1[] = "Velimir Radlovacki";
	char s2[20];
	strcpy(s2, s1);
	printf("s1: %s\ns2: %s", s1, s2);
}

Извршавањем овог програма добићемо:

s1: Velimir Radlovacki
s2: Velimir Radlovacki

strcat(s1, s2) – дописује стринг s2 на крај стринга s1. На пример:

#include <stdio.h>
#include <string.h>
int main(void)
{
	char s[80];
	strcpy(s, "Velimir ");
	strcat(s, "Radlovacki");
	puts(s);
}

Извршавањем овог програма добићемо:

Velimir Radlovacki

strcmp(s1, s2) – упоређује стрингове s1 и s2. Вредност (типа int) је: негативна ако текст из s1 испред текста из s2 по абецедном (лексикографском) поретку; већа од нуле ако је текст из s1 иза текста из s2; једнака нули ако су текстови из s1 и текстови из s2 једнаки. На пример, програм за погађање речи:

#include <stdio.h>
#include <string.h>
int main(void)
{
	char rec[] = "jabuka";
	char odgovor[80];
	do {
		printf("Pogodi moje omiljeno voce? : ");
		scanf("%s", odgovor);
	} while (strcmp(rec, odgovor) != 0);
	puts("Bravo! Pogodili ste");
}

strlen(s) – вредност (типа int) је број карактера у стрингу s (без NULL карактера).
strchr(s, c) – вредност (типа char*) је показивач на први елемент стринга s који садржи карактер c.
strrchr(s, c) – вредност (типа char*) је показивач на последњи елемент стринга s који садржи карактер c.
strstr(s1, s2) – вредност (типа char*) је показивач на последњи елемент стринга s1 почев од којег се стринг s2 појављује као подниз. Ако подниз није пронађен, вредност је NULL.

 

 

Фукције за конверзију стрингова у нумеричке типове

У заглављу stdlib.h налазе се функције за конверзију бројева из стринга у нумеричке типове. Неке од често коришћених су atoi(), atol() и atof().

 

Функција atoi()

Враћа вредност типа int добијену конверзијом стринга формата ±cccc у цео број (знак операције не мора бити присутан). Функција игнорише почетне размаке ако постоје, а ако није могуће извршити конверзију онда враћа нулу.

int atoi (const char * str);

 

ЗАДАТАК 1: Написати програм који са стандардног улаза учитава стринг s, конвертује га у цео број типа int и исписује на стандардни излаз. Подразумева се да ће корисник програма у стринг уносити цифре, где опционо први елемент може бити оператор + или оператор .

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	int x;
	char s[80];
	printf("Unesite broj: ");
	gets(s);
	x = atoi(s);
	printf("Uneli ste vrednost %d", x);
}

Овај програм можемо оптимизовати на следећи начин:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	char s[80];
	printf("Unesite broj: ");
	gets(s);
	printf("Uneli ste vrednost %d", atoi(s));
}

Након извршавања овог програма, ако корисник унесе стринг +12345, стринг ће бити конвертован у int и на стандардном излазу биће исписано 12345. Ако корисник унесе стринг -12345, након конверзије у int, на стандардном излазу биће исписано -12345.

Unesite broj: +12345
Uneli ste vrednost 12345
Unesite broj: -12345
Uneli ste vrednost -12345

 

ЗАДАТАК х. (ЗАДАТАК 72 из Приручника) Дат је код функције fun(…) написане у програмском језику Ц. Изабрати којој стандардној функцији одговара дата функција.

int fun(char* s) {
	int n, sign;
	while (*s == ' ' || *s == '\t') s++;
	sign = (*s == '-') ? -1 : 1;
	if (*s == '+' || *s == '-') s++;
	for (n = 0; *s >= '0' && *s <= '9'; s++) n = 10 * n + *s - '0';
	return (!*s) ? sign * n : 0;
}

1. isupper
2. isalpha
3. gets
4. strncat
5. atoi
6. strchr
7. strcmp

 

Функција atol()

Враћа вредност типа long int добијену конверзијом стринга формата ±cccc у цео број (знак операције не морају бити присутан). Функција игнорише почетне размаке ако постоје, а ако није могуће извршити конверзију онда враћа нулу.

long int atol ( const char * str );

 

ЗАДАТАК х. Написати програм који са стандардног улаза учитава стринг s, конвертује га у цео број типа long int и исписује на стандардни излаз. Подразумева се да ће корисник програма у стринг уносити цифре где опционо први елемент може бити оператор + или оператор .

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	char s[80];
	printf("Unesite broj: ");
	gets(s);
	printf("Uneli ste vrednost %ld", atol(s));
}

Након извршавања овог програма, ако корисник унесе стринг +12345, стринг ће бити конвертован у long int и на стандардном излазу биће исписано 12345. Ако корисник унесе стринг -12345, након конверзије у long int, на стандардном излазу биће исписано -12345.

Unesite broj: +12345
Uneli ste vrednost 12345
Unesite broj: -12345
Uneli ste vrednost -12345

 

Функција atof()

Враћа вредност типа double добијену конверзијом стринга формата ±ccc.cccE±ee у реалан број (знак операције, децимална тачка и све иза децималне тачке не мора бити присутнo). Функција игнорише почетне размаке ако постоје, а ако није могуће извршити конверзију онда враћа 0.0.

double atof (const char* str);

 

ЗАДАТАК х. Написати програм који са стандардног улаза учитава вредност у степенима у стринг s, потом конвертује s у реалан број типа double и на стандардни излаз исписује синус тог реалног броја.

#define _USE_MATH_DEFINES
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(void)
{
	char s[80];
	double x, sinx;
	printf("Unesite vrednost u stepenima: ");
	gets(s);
	x = atof(s);
	sinx = sin(x * M_PI / 180);
	printf("Sinus od %lf je %lf", x, sinx);
}

Тест примери:

Unesite vrednost u stepenima: 90
Sinus od 90.000000 je 1.000000
Unesite vrednost u stepenima: 180
Sinus od 180.000000 je 0.000000