Chuỗi ký tự trong C

cho em ko dùng ham strcpy để chép ký tự, mà dùng phép gán từng ký tự mà ko in ra được chuỗi k giống chuỗi s được ạ

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

int main()
{
	char s[30], k[30];
	gets(s);
	for(int i = 0; i < strlen(s); i++)
	{
		k[i] = s[i];
	}
	printf("\n%d\n", strlen(s));
	puts(s);
	printf("\n");
	puts(k);
	printf("\n%d", strlen(k));
}

Bạn thiếu ký tự \0

int i = 0;
for (; i < strlen(s); ++i)
  k[i] = s[i];
k[i + 1] = '\0';
4 Likes

là k[i] = ‘\0’ hay k[i+1] vậy anh,

i + 1 đó. Kí tự \0 luôn phải đặt sau kí tự cuối của chuỗi, sau khi thoát khỏi vòng lặp thì i sẽ có giá trị bằng độ dài của chuỗi vừa copy, +1 để thêm \0 vào. Hoặc có thể sử dụng luôn strlen(): k[strlen(s) + 1] = '\0';

Mà cách này không an toàn, chuỗi >= 30 sẽ bị tràn. Học cấp phát bộ nhớ để hiểu rõ hơn.

5 Likes

Thực ra thân hàm strcpy có thể chỉ có một dòng:

while(*p++ = *q++);

Đây cũng là cách nhớ *++.

1 Like

khi cấp phát bộ nhớ động thì khi nhập tên làm sao em biết được kích thước chuỗi ban đầu bằng bao nhiêu cấp phát thế a, hay ta cấp 1 kích cỡ N rồi realloc lại ạ. Như e làm thế này đã được chưa a

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *Tachho(char *hoten);
int main()
{
	char *Hoten = (char *) malloc(30 * sizeof(char));
	char *Ho = (char *) malloc(10 * sizeof(char));
	gets(Hoten);
	realloc(Hoten, strlen(Hoten) * sizeof(char));
	Ho = Tachho(Hoten);
	realloc(Ho, strlen(Ho) * sizeof(char));
	printf("\n%d\n", strlen(Hoten));
	puts(Hoten);
	printf("\n%d\n", strlen(Ho));
	puts(Ho);
}
char *Tachho(char *Hoten)
{ 
	int i = 0;
	char *Ho = (char *)malloc(10 * sizeof(char));
	for(;i < strlen(Hoten);i ++)
	{
		if(Hoten[i] == ' ') break;
		Ho[i] = Hoten[i];
	}
	Ho[i] = '\0';
	realloc(Ho, (i) * sizeof(char));
	return Ho;
}

Để làm mảng tự co giãn thì phải xác định kích thước khi khởi tạo và khi nào thì giãn hay co. Thường mảng sẽ giãn theo phương trình: new_capacity = old_capacity * f(old_capacity) với f là step function. Để dễ hình dung, ta xét f(x) = 1 + e^(-x/c).

Phần nhập từ bàn phím thì dùng fgets cho vào buffer trước rồi strlen cho đến hết, nhưng có đk thì lúc nào cũng có size đầu tiên.

1 Like

Một cách là bạn có thể đểm từ 0 tới khoảng trắng đầu tiên để xác định kích thước cần malloc(), cách khác là dùng strtok() để tách Nguyen Van A thành "Nguyen", `"Van", "A" rồi in ra cái đầu tiên.

#include <stdio.h>
#include <stdlib.h>

static const int N = 512;

static char *nhap_ten()
{
  char *ten = (char *) malloc(N * sizeof(char));
  gets(ten); // gets() để dễ minh họa
  
  return ten;
}

static char *tach_ho(char *ten)
{
  int i = 0;
  for (; i < strlen(ten); ++i)
  {
    if (ten[i] == ' ')
    {
      char *ho = (char *) malloc((i + 1) * sizeof(char));
      memcpy((char *) ho, (char *) ten, i);
      ho[i] = 0;
      
      return ho;
    }
  }
  
  return "?";
}

int main()
{
  char *ten = nhap_ten();
  char *ho = tach_ho(ten);
  
  printf("ten = %s; ho = %s\n", ten, ho);
  
  free(ten);
  free(ho);
}

Chương trình đơn giản thì 1 lần malloc() rồi free() thôi, quản lý bộ nhớ là một thứ lằng nhằng.

4 Likes

Em cám ơn a, cho em hỏi thêm là từ khóa static có ý nghĩa gì vậy ạ

cái này e thấy khó hiểu quá anh

static char *nhap_ten() {...}

Trong ngữ cảnh này thì static có nghĩa là “đừng đem nhap_ten() ra ngoài module khác, chỉ dùng nội bộ trong phạm vi của file này” (chính xác hơn, là translation unit).

Cái này thì tùy người, bạn có thể không dùng nếu thấy không cần, tuy nó là thói quen (practice) tốt.

4 Likes

vâng anh, cho em hỏi nữa là trong hàm main anh giải phóng ‘ten’ và ‘ho’ là giải phóng luôn bộ nhớ mà mình cấp phát ở hàm con phải không a. CÓ phải là do 2 con trỏ chỉ đến nhau thì mình giải phóng một thằng thì con trỏ kia cũng giải phóng không ạ

Đúng rồi, cấp phát ở đâu thì phải free sau đó. Còn nếu 2 pointer trỏ tới nhau thì khi 1 con trỏ bị giải phóng thì con trỏ kia sẽ trỏ tới 1 giá trị không xác định, gọi là rác:

#include <stdio.h>

int main()
{
  int *x = (int *) malloc(sizeof(int)); /* x trỏ tới giá trị 42 */
  *x = 42;
  
  int *y = x; /* y trỏ tới x -> y cũng trỏ tới vùng nhớ mà x trỏ tới */
  
  printf("y = %i\n", *y); /* y = 42 */
  free(x); /* giải phóng x */
  printf("y = %i\n", *y); /* y = rác */
}

y vẫn sẽ trỏ tới ô nhớ mà x trỏ tới trước đó, nhưng ô nhớ này đã bị free() và bị viết chồng lên một giá trị ngẫu nhiên.

4 Likes

Vậy phần ở trên anh cấp phát bộ nhớ ở các hàm con, khi vào hàm main() anh dùng xong vẫn giải phóng được ạ

Giữ được con trỏ là được.

3 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?