List
2.5.5 Arrays as Strings
You can use an array of characters to hold a string (see String Constants). The array may be built of either signed or unsigned characters.
When you declare the array, you can specify the number of elements it will have. That number will be the maximum number of characters that should be in the string, including the null character used to end the string. If you choose this option, then you do not have to initialize the array when you declare it. Alternately, you can simply initialize the array to a value, and its size will then be exactly large enough to hold whatever string you used to initialize it.
There are two different ways to initialize the array. You can specify of comma-delimited list of characters enclosed in braces, or you can specify a string literal enclosed in double quotation marks.
Here are some examples:
char blue[26];
char yellow[26] = {'y', 'e', 'l', 'l', 'o', 'w', '\0'};
char orange[26] = "orange";
char gray[] = {'g', 'r', 'a', 'y', '\0'};
char salmon[] = "salmon";
In each of these cases, the null character \0 is included at the end of the string, even when not explicitly stated. (Note that if you initialize a string using an array of individual characters, then the null character is not guaranteed to be present. It might be, but such an occurrence would be one of chance, and should not be relied upon.)
After initialization, you cannot assign a new string literal to an array using the assignment operator. For example, this will not work:
char lemon[26] = "custard";
lemon = "steak sauce"; /* Fails! */
However, there are functions in the GNU C library that perform operations (including copy) on string arrays. You can also change one character at a time, by accessing individual string elements as you would any other array:
char name[] = "bob"; // bob
name[0] = 'r'; // rob
It is possible for you to explicitly state the number of elements in the array, and then initialize it using a string that has more characters than there are elements in the array. This is not a good thing. The larger string will not override the previously specified size of the array, and you will get a compile-time warning. Since the original array size remains, any part of the string that exceeds that original size is being written to a memory location that was not allocated for it.
@see https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Arrays-as-Strings
2.6.2 Initializing Pointers
You can initialize a pointer when you first declare it by specifying a variable address to store in it. For example, the following code declares an int variable ‘i’, and a pointer which is initialized with the address of ‘i’:
int i;
int *ip = &i;
Note the use of the address operator (see Pointer Operators), used to get the memory address of a variable. After you declare a pointer, you do not use the indirection operator with the pointer’s name when assigning it a new address to point to. On the contrary, that would change the value of the variable that the points to, not the value of the pointer itself. For example:
int i, j;
int *ip = &i; /* ‘ip’ now holds the address of ‘i’. */
ip = &j; /* ‘ip’ now holds the address of ‘j’. */
*ip = &i; /* ‘j’ now holds the address of ‘i’. */
The value stored in a pointer is an integral number: a location within the computer’s memory space. If you are so inclined, you can assign pointer values explicitly using literal integers, casting them to the appropriate pointer type. However, we do not recommend this practice unless you need to have extremely fine-tuned control over what is stored in memory, and you know exactly what you are doing. It would be all too easy to accidentally overwrite something that you did not intend to. Most uses of this technique are also non-portable.
It is important to note that if you do not initialize a pointer with the address of some other existing object, it points nowhere in particular and will likely make your program crash if you use it (formally, this kind of thing is called undefined behavior).
@see https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Initializing-Pointers
3.10 Pointer Operators
You can use the address operator & to obtain the memory address of an object.
int x = 5;
int *pointer_to_x = &x;
It is not necessary to use this operator to obtain the address of a function, although you can:
extern int foo (void);
int (*fp1) (void) = foo; /* fp1 points to foo */
int (*fp2) (void) = &foo; /* fp2 also points to foo */
Function pointers and data pointers are not compatible, in the sense that you cannot expect to store the address of a function into a data pointer, and then copy that into a function pointer and call it successfully. It might work on some systems, but it’s not a portable technique.
As a GNU extension to C89, you can also obtain the address of a label with the label address operator &&. The result is a void* pointer which can be used with goto. See The goto Statement.
Given a memory address stored in a pointer, you can use the indirection operator * to obtain the value stored at the address. (This is called dereferencing the pointer.)
int x = 5;
int y;
int *ptr;
ptr = &x; /* ptr now holds the address of x. */
y = *ptr; /* y gets the value stored at the address
stored in ptr. */
Avoid using dereferencing pointers that have not been initialized to a known memory location.
@see https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Pointer-Operators
5.4 Function Parameters
Function parameters can be any expression—a literal value, a value stored in variable, an address in memory, or a more complex expression built by combining these.
Within the function body, the parameter is a local copy of the value passed into the function; you cannot change the value passed in by changing the local copy.
int x = 23;
foo (x);
…
/* Definition for function foo. */
int foo (int a)
{
a = 2 * a;
return a;
}
In that example, even though the parameter a is modified in the function ‘foo’, the variable x that is passed to the function does not change. If you wish to use the function to change the original value of x, then you would have to incorporate the function call into an assignment statement:
x = foo (x);
If the value that you pass to a function is a memory address (that is, a pointer), then you can access (and change) the data stored at the memory address. This achieves an effect similar to pass-by-reference in other languages, but is not the same: the memory address is simply a value, just like any other value, and cannot itself be changed. The difference between passing a pointer and passing an integer lies in what you can do using the value within the function.
Here is an example of calling a function with a pointer parameter:
void
foo (int *x)
{
*x = *x + 42;
}
…
int a = 15;
foo (&a);
The formal parameter for the function is of type pointer-to-int, and we call the function by passing it the address of a variable of type int. By dereferencing the pointer within the function body, we can both see and change the value stored in the address. The above changes the value of a to ‘57’.
Even if you don’t want to change the value stored in the address, passing the address of a variable rather than the variable itself can be useful if the variable type is large and you need to conserve memory space or limit the performance impact of parameter copying. For example:
struct foo
{
int x;
float y;
double z;
};
void bar (const struct foo *a);
In this case, unless you are working on a computer with very large memory addresses, it will take less memory to pass a pointer to the structure than to pass an instance of the structure.
One type of parameter that is always passed as a pointer is any sort of array:
void foo (int a[]);
…
int x[100];
foo (x);
In this example, calling the function foo with the parameter a does not copy the entire array into a new local parameter within foo; rather, it passes x as a pointer to the first element in x. Be careful, though: within the function, you cannot use sizeof to determine the size of the array x—sizeof instead tells you the size of the pointer x. Indeed, the above code is equivalent to:
void foo (int *a);
…
int x[100];
foo (x);
Explicitly specifying the length of the array in the parameter declaration will not help. If you really need to pass an array by value, you can wrap it in a struct, though doing this will rarely be useful (passing a const-qualified pointer is normally sufficient to indicate that the caller should not modify the array).
@see https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Function-Parameters
# rand() example
/*
* gcc -Wall -lrt z.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int _rand_int(int min, int max);
int rand_int(int min, int max);
int rand_int2(int min, int max);
int main(void) {
int i, r1, r2, min = 10, max = 20;
r1 = rand_int(min, max);
r2 = rand_int2(min, max);
printf("r1=%d,r2=%d\n", r1, r2);
return 0;
}
int _rand_int(int min, int max) {
return (rand() % (max - min + 1)) + min;
}
int rand_int(int min, int max) {
srand(time(NULL));
return _rand_int(min, max);
}
int rand_int2(int min, int max) {
struct timespec t1;
clock_gettime(CLOCK_MONOTONIC, &t1);
//printf("%llu, %lu\n", (unsigned long long) t1.tv_sec, t1.tv_nsec);
srand(t1.tv_nsec);
return _rand_int(min, max);
}
#include <stdio.h>
#include <string.h>
int _tolower(int i) {
return (65 <= i && i <= 90) ? i + 32 : i;
}
int _strlen(char *str) {
int i;
for(i = 0; str[i] != '\0'; i++);
return i;
}
int __strcmp(char *a, char *b, int c) {
int i, j;
int ret;
int la = _strlen(a);
int lb = _strlen(b);
int size = (la > lb) ? la : lb;
for(i = 0; i < size; i++) {
if (c) { //case sensitive
ret = ((i < la) ? a[i] : 0) - ((i < lb) ? b[i] : 0);
} else { //case insensitive
ret = ((i < la) ? _tolower(a[i]) : 0) - ((i < lb) ? _tolower(b[i]) : 0);
}
if ( ret != 0 ) {
break;
}
}
return ret;
}
int _strcmp(char *a, char *b) {
return __strcmp(a, b, 1);
}
int _strcasecmp(char *a, char *b) {
return __strcmp(a, b, 0);
}
int main() {
int i;
char a = 'A';
char b = 'a';
char n1[6] = "abcd";
//char n2[6] = {'a','b','c','d'};
char n2[6] = "ABcde";
printf("1.%c=%d, %c=%d\n", a, a, b, b);
if ( _tolower(a) == _tolower(b)) {
printf("same\n");
} else {
printf("!same\n");
}
printf("n1=%s, n2=%s\n", n1, n2);
printf("strcasecmp():%d, _strcasecmp(): %d, strcmp():%d, _strcmp():%d\n",
strcasecmp(n1, n2),
_strcasecmp(n1, n2),
strcmp(n1, n2),
_strcmp(n1, n2)
);
/*
char s1[10] = "azz";
char s2[10] = "Boy";
printf("%s:%s=%d\n", s1,s1, strcasecmp(s1,s1));
printf("%s:%s=%d\n", s1,s2, strcasecmp(s1,s2));
printf("%s:%s=%d\n", s2,s1, strcasecmp(s2,s1));
*/
return 0;
}
# Pointer
int i;
int *p = &i; //when initialize with declation
--------------
int i;
int *p;
p = &i; // when initialize after declation
--------------