Jump to content

[C] Strings


entering

Recommended Posts

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]

Link to comment
Share on other 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'.

Link to comment
Share on other 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 😁, vou continuar a ler....

(...)

Gostei, simples claro e eficaz.

Tenho mais algumas sugestões, agora que acabei de ler 👍 , 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)

Link to comment
Share on other sites

  • 2 years later...
  • 3 weeks later...

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.

Link to comment
Share on other 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 ... 😛

Link to comment
Share on other sites

  • 3 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.