• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

entering

[C] Strings

19 mensagens neste tópico

Introdução

Uma string é um conjunto de caracteres armazenados num vector.

As strings são representadas utilizando aspas enquanto os caracteres entre plicas.

Poderemos pensar que C é fraco no tratamento de strings visto que strings não é tipo básico da linguagem e única forma de representar um conjunto de caracteres é recorrendo a um vector.

Por exemplo não podemos fazer:

  • uma atribuiçao s1="OLA"; (apenas podemos fazer isto na declaração);
  • compará-las s1=="OLA";
  • concatenar.

No entanto C possui uma poderosa biblioteca de funções que permite realizar estas tarefas e muito mais, e se por acaso não encontrarmos nenhuma função que faça o que queremos podemos sempre fazer manipulação carácter a carácter e resolver o problema (algumas linguagens que tratam strings como um todo e não um conjunto de caracteres não o permitem).

A declaração de strings obedece à sintaxe de declaração de vectores, sendo a primeira posição 0.

Uma string termina no carácter \0.

NOTA: Na declaração de uma string não se esqueça de 'guardar' espaço para o \0.

Exemplo:

char linha[101]; : Declaração de um vector que conterá uma string com 100 caracteres e um para o \0.

Referi em cima que não é possível fazer uma atribuição deste estilo s1="OLA";.

No entanto ao ser declarada pode ser atribuída uma string. Exemplo:

char nome[]="OLA"; : Equivalente a char nome[3+1]="OLA";.

Leitura e escrita se strings

#include <stdio.h>

int main (void) {
 char palavra[]="OLA";
 printf("%s\n",palavra);
 puts(palavra);
 return 0;
}

*Nota a função puts após escrever uma string muda de linha, enquanto a função printf não (a função puts (put string) só permite a escrita de strings tal como o nome indica).

#include <stdio.h>

int main (void) {
 char s[20];
 scanf("%s",s);
 printf("%s",s);
 return 0;
}

*Nota: não é precedida de um & ao contrário de outro tipo de variáveis (scanf).

A função scanf lê todos os caracteres até encontrar um espaço ou enter, em seguida coloca o \0 (ou seja, só permite ler uma palavra).

Cuidado ao usarem por causa de seg faults.

$ ./a.out
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault (core dumped)

Isto porque o input ultrapassou os 20 caracteres, isto acontece quando um programa tenta aceder a memória que não lhe é destinada.

A funçao gets (get string) permite colocar numa variável todos os caracteres introduzidos pelo utilizador (desde que dentro do limite), ou seja, não está limitada a leitura de uma única palavra como a função scanf. Sintaxe: gets(nome_da_var);. Tal como o scanf também tem o problema dos seg faults.

Recomendo sempre o uso da função fgets!

char *fgets(char *s, int n, FILE *stream);

É retornado NULL se algum erro acontecer.

Para ler do stdin (standard input): fgets(s, MAX-CARACTERES, stdin);.

Atenção que ao contrário do scanf, que "suprime" o \n, o fgets não faz isso.

Mais a frente iremos ver uma maneira simples de se necessário "retirar" o \n.

Algumas funções para manipulação de strings, #include <string.h>

strlen

int strlen (char *s)

Devolve o número de caracteres existentes numa string sem contar com o \0.

#include <stdio.h>
#include <string.h>

int main (void) {
 char str[]="Olá Mundo";
 printf ("%i\n",strlen(str));
 return (0);
}

O código desta função seria algo deste género:

#include <stdio.h>

int strlen (char *s) {
 int i;
 for (i=0;s[i]!='\0';++i);
 return i;
}

strcpy

char * strcpy ( char * dest, const char * src );

Esta função copia a string src para dest e retorna dest.

#include <stdio.h>
#include <string.h>

int main (void) {
 char str[20];
 printf ("%s\n",strcpy(str,"Olá Mundo"));
 return (0);
}

O código de strcpy poderá ser algo deste género:

char *strcpy (char *dest, char *src) {
 int i=0; // Variável inicializada a 0 para apontar para a primeira posição
 while (dest[i]=src[i]) /* dest[i]=src[i] não é um teste de igualdade mas sim uma atribuição, como se trata de uma atribuição o carácter atribuído é devolvido, se for o carácter terminador sai do while */
   ++i;
 return dest;
}

strcat

char *strcat (char * dest, const char * src);

Coloca a string src imediatamente a seguir ao final da string dest e retorna dest.

#include <stdio.h>
#include <string.h>

int main (void) {
 char str[20]="Olá ";
 printf ("%s\n",strcat(str,"Mundo"));
 return (0);
}

O código da strcat poderá ser algo deste género:

char *strcat (char *dest, char *src) {
 int i=0,len=strlen(dest);
 while (dest[len++]=src[i++]);
 return dest;
}

memset

void * memset ( void * buffer, int c, size_t n );

Altera os primeiros n bytes de buffer pelo valor c.

#include <stdio.h>
#include <string.h>

int main (void) {
 char str[]="Quase todos os programadores devem conheçer o memset.";
 memset (str,'-',5);
 puts (str);
 return (0);
}

$ ./a.out
----- todos os programadores devem conheçer o memset.

memcpy

void * memcpy ( void * dest, const void * src, size_t num );

Copia num bytes de src para dest.

#include <stdio.h>
#include <string.h>

int main (void) {
 char str1[]="Ola ...",str2[5];
 memcpy (str2,str1,3);
 puts (str2);
 return (0);
}

[Artigo no Wiki]

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

de facto deveria ser dest[ i ]=src[ i ]

bons olhos TheDark :o

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

LOL

Fizeste a mesma coisa. Cuidado com os [ i ], metam espaços la dentro ou metam em code :thumbsup:

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Pois, eu pensei que ele se tinha esquecido de os colocar, e não me lembrei que fosse devido ao BBCode :/

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

uma função de manipulação de strings bastante útil e que não foi mencionada é a 'strdup'

char* strdup(const char* str)

esta função copia uma string, mas ao contrário da 'strcpy', não é necessário alocar espaço previamente...

exemplo

#include <stdio.h>
#include <string.h>

int main()
{
  char str1[]="exemplo";
  char* str2;

  str2=strdup(str1);

  puts(str2);

  free(str2);

  return 0;
}

caso quisesse usar a função 'strcpy' teria que declarar 'str2' como um array ou então alocar o espaço dinâmicamente (através de um 'calloc' ou algo parecido).

quando usamos a função 'strdup' e deixamos de precisar da variável para onde foi copiada a string devemos libertar o espaço por ela ocupado com o 'free'.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Como moderador desta secção, peço que cada vez que façam referência a alguma função pré declarada, que exponham a sua constituição por favor.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

ainda nao acabei de escrever sobre strings irei referir a strdup, já conheçia mas nem me tinha lembrado dela, mas tens razão bastante útil :thumbsup:

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Ainda não tive tempo para ler tudo mas deixa-me fazer uma sugestão antes que me esqueça.

Substitui :

Uma string é um conjunto de caracteres armazenados num vector.

Por:

"Uma string é um vector de caracters terminados pelo caracater '\0'"

Eu sei que dizes isso mais abaixo, mas titulos dão sempre impacto :cheesygrin:, vou continuar a ler....

(...)

Gostei, simples claro e eficaz.

Tenho mais algumas sugestões, agora que acabei de ler :thumbsup:, não me preocupei com erros de código, acho até que ao existirem ajudam muito quem quer aprender, claro desde que nãosejam em demasia....

'segmentation fault' são, neste caso, o resultado de 'buffer overflows' que estão muito ligados ao uso de strings e que são muito dificeis de detectar, no entanto nem sempre uma escrita errada na memória provoca 'segmentation fault', por vezes um simples 'scanf' provoca comportamentos estranhos em toda a aplicação.

O uso da função 'fgets' ajuda muito mas não elimina por completo o perigo de 'buffer overflow'.

'memset' embora muito útil é uma função perigosa, especialmente para quem começa B)

Bem, concluíndo, está muito bom, fico à espera da continuação B)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

ja agora podem-me me responder se no caso de fgets para um string ele inclui o caracteres de terminação \0 ?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

ja agora podem-me me responder se no caso de fgets para um string ele inclui o caracteres de terminação \0 ?

O '\0' tem que lá estar, senão não saberás onde termina a string.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Para ler do stdin (standard input) fgets (s,MAX-CARACTERES,stdin);

Atenção que ao contrário do scanf que 'suprime' o \n o fgets não faz isso.

Mais a frente iremos ver uma maneira simples de se necessário 'retirar' o \n

pff alguem me pode explicar como faço isso? Precisava de saber com alguma urgência. Já ando com a cabeça nisto há algumas horas.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

pff alguem me pode explicar como faço isso? Precisava de saber com alguma urgência. Já ando com a cabeça nisto há algumas horas.

Uma maneira é:

variavel[strlen(variavel)-1] = '\0';

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Obrigado, mas ainda assim continuo com um problema...

estou a fazer o meu primeiro programa recorrendo a manipulação de ficheiros, ainda não domino muito bem essa área.

mas pronto, o objectivo desta função é apenas receber um Username e uma password do utilizador e de seguida, ler as dados contidos no ficheiro .txt onde anteriormente "criou uma conta".

depois disso compara as duas strings, para o caso de ele inserir um username ou password inválidas.

posto aqui a função:

login()
{
char username[25], username_file[25];	        /*vector que recebe os dados lidos do ficheiro*/
int password, password_file;                  	/*variavel que recebe os dados lidos do ficheiro*/
FILE *fp = fopen("base_dados.txt", "r");

printf("\t     |||||||||||||||    ||||||||||||||     ||||||||||||||||\n");
printf("\t     ||||||||||||||||   |||||||||||||||    ||||||||||||||||\n");
printf("\t     ||||        ||||   ||||       ||||    |||||\n");
printf("\t     ||||       ||||    ||||      |||||    |||||\n");
printf("\t     ||||||||||||||     ||||||||||||||     ||||||||||\n");
printf("\t     ||||||||||||||     |||||||||||||      ||||||||||\n");
printf("\t     |||||||||||||||    |||||||||||        ||||||||\n");
printf("\t     ||||      ||||||   |||||              |||||\n");
printf("\t     ||||       |||||   |||||              |||||\n");
printf("\t     |||||||||||||||    |||||              |||||\n");
printf("\t     ||||||||||||||     |||||              |||||\n");
printf("\t\t\t<Banco de Planeamento Financeiro>\n");

do
{
	while(getchar()!='\n');					//limpar o buffer
	puts("Nome de Utilizador: ");	
	gets(username);							//recebe o Username do utilizador
	puts("Password: ");
	scanf("%d", &password);					// recebe a password do utilizador

	fgets(username_file,MAX_LINHA,fp);		// le o nome de utilizador do ficheiro
	fscanf(fp, "%d", &password_file);		        // le a password do ficheiro

	username_file[strlen(username_file)-1] = '\0';

	if(username != username_file || password != password_file)   // comparação das strings
		printf("Nome de Usuario/Password Invalidos. Pff volte a inserir:\n");
	else
		printf("Login efectuado com sucesso!   Dentro de breves instantes sera redireccionado...");
       }
while (username_file != username || password_file != password);
fclose(fp);
Sleep(2500);
}

o problema, é que na altura de comparaçao das strings de Usernames, dá inválido!  já confirmei e é mesmo das strings pois as passwords estao a funcionar.

acredito que hajam maneiras mais fáceis e mais eficazes de efectuar a mesma coisa que isto...se puderem dar uma ajudinha ... :P

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora