CppReference - Strict Aliasing.strlen为提升性能,应将其修改为:
for (size_t i = 0, n = strlen(s); i < n; ++i)
// ...
通过预先计算字符串长度并将其存储在变量 n 中,循环可以在线性时间
strlenfor (int i = 0; i < strlen(s); ++i)
// ...
为什么编译器会对 i < strlen(s) 发出警告?
strlen 的返回类型是 size_t,这是一种无符号整数类型。int 和 size_t 之间执行操作或比较时,int 值会被隐式转换为 size_t。
i 为负数(例如 -1),比较 -1 < strlen(s) 几乎肯定会被判定为 false(假)。* 应避免混合使用有符号和无符号整数。
strcpySignature: (Defined in header <string.h>)
char *strcpy(char* dest, const char* src);
Behavior:
strcpy 函数将以 src 指向的空终止字节字符串(包括空终止符 \0)复制到以 dest 指向其首元素的字符数组中。dest 数组不够大,无法容纳 src 的内容。dest 不是指向字符数组的指针,或 src 不是指向空终止字节字符串的指针。strcpy Functionchar *strcpy(char* dest, const char* src);
Most people cannot resist the urge to use indexing and thus call strlen first:
char *strcpy(char *dest, const char *src) {
size_t length = strlen(src);
for (size_t i = 0; i <= length; ++i)
dest[i] = src[i];
return dest;
}
However, strlen also scans the src string.
It is possible to scan only once: the termination condition should be when encountering '\0', rather than i == strlen(src).
char *strcpy(char *dest, const char *src) {
size_t i = 0;
while (src[i] != '\0') {
dest[i] = src[i];
++i;
}
dest[i] = '\0';
return dest;
}
You can directly manipulate pointers without needing indexing.
dest and src are local variables within your function, so you can modify them freely!char *strcpy(char *dest, const char *src) {
char *ret = dest;
while (*src != '\0')
*dest++ = *src++;
*dest = '\0';
return ret;
}
char a[100], b[] = "hello";
strcpy(a, b); // This works fine.
malloc, callocvoid* malloc(size_t size);
void* calloc(size_t num, size_t each_size);
malloc:分配 size 字节的未初始化内存,这意味着所分配元素的值是不确定的。
calloc:为 num 个对象(每个大小为 each_size)分配内存,并将所有字节初始化为零。
num * size。0.0 或指针被设置为空指针值。malloc根据 C 标准,malloc 分配的内存包含不确定的值,但在实践中,这些值通常表现为零。这仅仅是巧合吗?
一般来说不是!
更多详细信息,您可以查看 StackOverflow 上的这个回答。
#include <stdio.h>
#include <stdlib.h>
int main() {
int n = 5;
int *arr = malloc(n * sizeof(int));
printf("Array values:\n");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
return 0;
}
realloc: reallocates a specified area of memoryvoid* realloc(void* ptr, size_t new_size);
参数 ptr 可以是 NULL,也可以是由 malloc、calloc 或 realloc 先前分配且尚未通过调用 free 或 realloc 释放的指针。
ptr 为 NULL,则行为等同于 malloc(new_size)。ptr 不为 NULL,则通过以下方式执行分配:
ptr 指向的现有内存区域,或new_size 字节的新内存块,复制新旧大小中较小者所对应的内存内容,并释放旧内存块。如果可用内存不足,旧内存块不会被释放,并返回空指针。
malloc, calloc, and realloc为避免内存泄漏,这些函数返回的任何指针都必须使用 free(或 realloc)进行释放。需要注意的是,原始指针 ptr 在重新分配后即失效,后续对其的任何访问都会导致未定义行为——即使重新分配是原地进行的。
malloc(0)、calloc(0, N)、calloc(N, 0) 和 realloc(ptr, 0) 的行为是由实现定义的。
free: void free(void* ptr)正确操作:
ptr != NULL。未定义行为:
free 释放后,继续使用或再次释放该悬垂指针。malloc、calloc、realloc 或 C11 的 aligned_alloc 返回的指针。
提醒:
忘记调用 free 会导致内存泄漏,这可能使您无法通过在线评测平台(OJ)的测试。
memcpyungetc
int **p = malloc(sizeof(int *) * n);
for (int i = 0; i != n; ++i)
p[i] = malloc(sizeof(int) * m);
for (int i = 0; i != n; ++i)
for (int j = 0; j != m; ++j)
p[i][j] = /* ... */
for (int i = 0; i != n; ++i)
free(p[i]);
free(p);
int *p = malloc(sizeof(int) * n * m);
for (int i = 0; i != n; ++i)
for (int j = 0; j != m; ++j)
p[i * m + j] = /* ... */
// ...
free(p);
假设我们需要读取一个未知长度的非空白字符序列。在这种情况下,我们可以使用 malloc 动态分配内存,并根据需要使用 realloc 调整其大小。具体步骤包括:
// Snippet 1
char *read_string(void) {
// ignore leading whitespaces
char c = getchar();
while (isspace(c))
c = getchar();
char *buffer = malloc(INITIAL_SIZE);
int capacity = INITIAL_SIZE;
int cur_pos = 0;
// Snippet 2
while (!isspace(c)) {
if (cur_pos == capacity - 1) {
char *new_buffer = malloc(capacity * 2);
// copy everything what we have stored
// to the new buffer
memcpy(new_buffer, buffer, cur_pos);
// Don't forget to free.
free(buffer);
capacity *= 2;
buffer = new_buffer;
}
buffer[cur_pos++] = c;
c = getchar();
}
// Snippet 3
// Now, c is a whitespace. This is not part of the contents we need.
ungetc(c, stdin); // Put that whitespace back to the input.
buffer[cur_pos] = '\0'; // Remember this!!
return buffer;
}
memcpyDefined in header <string.h>:
void* memcpy(void* dest, const void* src, size_t count);
count 个字符从 src 指向的内存位置复制到 dest 指向的内存位置。返回 dest。dest 没有足够的空间容纳 count 个字符src, 和 dest 的内存区域重叠src 或 dest 是无效指针或空指针memcpy 比 strcpy 更快,因为 strcpy 遇到 \0 会停止复制,而 memcpy 会不检查数据内容地精确复制指定数量的字节ungetcint ungetc(int ch, FILE* stream); // defined in header <stdio.h>
ungetc 将字符 ch 推回输入流 stream 的缓冲区中。下一次从该流读取操作将会获取到这个被推回的字符。
ungetc,其行为是由实现定义的(implementation-defined),并且可能会失败。ungetc 调用,被推回的字符将以逆序被读取。