01/10/2018, 15:52

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("
%d
", strlen(s));
	puts(s);
	printf("
");
	puts(k);
	printf("
%d", strlen(k));
}

Florastamine viết 18:03 ngày 01/10/2018

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

int i = 0;
for (; i < strlen(s); ++i)
  k[i] = s[i];
k[i + 1] = '\0';
Đạt viết 18:04 ngày 01/10/2018

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

Florastamine viết 17:59 ngày 01/10/2018

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.

rogp10 viết 17:57 ngày 01/10/2018

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ớ *++.

Đạt viết 17:58 ngày 01/10/2018

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;
}
rogp10 viết 18:06 ngày 01/10/2018

Để 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.

Florastamine viết 18:07 ngày 01/10/2018

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.

Đạt viết 18:00 ngày 01/10/2018

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

Đạt viết 17:55 ngày 01/10/2018

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

Florastamine viết 18:08 ngày 01/10/2018
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.

Đạt viết 17:57 ngày 01/10/2018

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 ạ

Florastamine viết 18:04 ngày 01/10/2018

Đú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.

Đạt viết 18:08 ngày 01/10/2018

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 ạ

rogp10 viết 17:54 ngày 01/10/2018

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

Bài liên quan
0