C语言第三章Functions, Arrays & Pointers

本文详细介绍了C语言中函数的声明、定义与参数传递,包括默认的值传递方式和参数作用域。接着讲解了变量的作用域,特别是静态变量的特点。递归函数的概念和实现也被阐述,以及如何防止无限循环。数组部分涵盖了单、二维数组的声明、初始化和访问。最后,深入探讨了指针的用法,包括指针变量、指针与数组的关系、指针与函数的交互,以及地址运算和指针算术。
摘要由CSDN通过智能技术生成

Functions

Functions in C

Declarations usually appear above the main() function and take the form:

return_type function_name(parameters); 

The return_type is the type of value the function sends back to the calling statement. The function_name is followed by parentheses. Optional parameter names with type declarations are placed inside the parentheses.
A function is not required to return a value, but a return type must still be in the declaration. In this case, the keyword void is used.
For example, the display_message function declaration indicates the function does not return a value: void display_message();
When the parameter types and names are included in a declaration, the declaration is called a function prototype(函数原型).
Function definitions(函数定义) usually appear after the main() function.

Function Parameters

Values are passed to these parameters as arguments through the function call.
By default, arguments are passed by value, which means that a copy of data is given to the parameters of the called function. The actual variable isn’t passed into the function, so it won’t change.
Arguments passed to a function are matched to parameters by position. Therefore, the first argument is passed to the first parameter, the second to the second parameter, and so on(依此类推).
The following program demonstrates(演示) parameters passed by value:

#include <stdio.h>

int sum_up (int x, int y); 

int main() {
    int x, y, result;
  
    x = 3;
    y = 12;
    result = sum_up(x, y);
    printf("%d + %d = %d", x, y, result);
    
    return 0;
}

int sum_up (int x, int y) { 
    x += y;
    return(x);
}

The program output is: 3 + 12 = 15
The values of x and y were passed to sum_up. Note that even though the value of parameter x was changed in sum_up, the value of argument x in main() was not changed because only its value was passed into the parameter x.
The parameters in a function declaration are the formal parameters(形式参数). The values passed to these parameters are the arguments, sometimes called the actual parameters(实际参数).

Variable Scope(作用域)

Variable scope refers to the visibility of variables within a program.
Variables declared in a function are local to that block of code and cannot be referred to outside the function.
Variables declared outside all functions are global to the entire program.
For example, constants declared with a #define at the top of a program are visible to the entire program.
When arguments are passed to function parameters, the parameters act as(充当) local variables. Upon exiting a function, parameters and any local variables in the function are destroyed.
Use global variables with caution. They should be initialized before using to avoid unexpected results. And because they can be changed anywhere in a program, global variables can lead to hard to detect errors.

Static Variables(静态变量)

Static variables have a local scope but are not destroyed when a function is exited. Therefore, a static variable retains(保留) its value for the life of the program(在程序的整个生命周期) and can be accessed every time the function is re-entered.
A static variable is initialized when declared and requires the prefix(前缀) static.

Recursive(递归的) Functions

A recursive function is one that calls itself and includes a base case, or exit condition, for ending the recursive calls. In the case of computing a factorial(阶乘), the base case is num equal to 1.

#include <stdio.h>

//function declaration
int factorial(int num);

int main() {    
    int x = 5;

    printf("The factorial of %d is %d\n", x, factorial(x));
 
    return 0;
}

//function definition
int factorial(int num) {
  
    if (num == 1)  /* base case */
        return (1);
    else
        return (num * factorial(num - 1));
}

Recursion works by “stacking” calls until the base case is executed. At that point, the calls are completed from newest to oldest. The factorial call stack can be thought of as:
2factorial(1)
3
factorial(2)
4factorial(3)
5
factorial(4)
When the base case is reached, the return value 1 triggers(触发) the completion of the stacked calls. The return values from newest to oldest creates the following calculations, with the final calculation (5 * 24) being returned to the calling function main():
2 * 1
3 * 2
4 * 6
5 * 24
A recursive solution requires a base case to prevent an infinite loop.

Arrays

Arrays in C

An array is a data structure that stores a collection(集合) of related values that are all the same type.
Arrays are useful because they can represent related data with one descriptive name rather than using separate variables that each must be named uniquely.
For example, the array test_scores[25] can hold 25 test scores.
An array declaration includes the type of the values it stores, an identifier(标识符), and square brackets [ ] with a number that indicates the array size.
For example:

int test_scores[25]; /* An array size 25 */

You can also initialize an array when it is declared, as in the following statement:

float prices[5] = {3.2, 6.55, 10.49, 1.25, 0.99};

Note that initial values are separated by commas and placed inside curly braces { }.
An array can be partially initialized, as in:

float prices[5] = {3.2, 6.55};

Missing values are set to 0.
An array is stored in contiguous(连续的) memory locations and cannot change size after being declared.

Accessing Array Elements

The contents of an array are called elements with each element accessible by an index number.
In C, index numbers start at 0.
An array with 5 elements will have index numbers 0, 1, 2, 3, and 4.
To access an array element, refer to its index number.
The index of an array is also referred to as the subscript.

Using Loops with Arrays

Many algorithms require accessing every element of an array to check for data, store information, and other tasks. This can be done in a process called traversing the array, which is often implemented with a for loop because the loop control variable naturally corresponds to array indexes.
The loop control variable iterates from 0 to one less than the number of elements(比元素数少1) to match index values.

Two-Dimensional Arrays

A two-dimensional array is an array of arrays and can be thought of as a table. You can also think of a two-dimensional array as a grid for representing a chess board(棋盘), city blocks(城市街区), and much more.
A two-dimensional array declaration indicates the number of number rows and the number of columns.

int a[2][3]; /* A 2 x 3 array */

Nested curly braces are used to initialize elements row by row, as in the following statement:

int a[2][3] = {
  {3, 2, 6},
  {4, 5, 20}
};

The same statement can also take the form:

int a[2][3] = { {3, 2, 6}, {4, 5, 20} };

The former statement offers more clarity with visualizing the structure of the array.
An array can have more than two dimensions. For example, a[5][3][4] is an array that has 5 elements that each store 3 elements that each store 4 elements.

Accessing Two-Dimensional Arrays

Just as a for loop is used to iterate through a one-dimensional array, nested for loops are used to traverse a two-dimensional array

Pointers

Using Memory

C is designed to be a low-level language that can easily access memory locations and perform memory-related operations.
For instance, the scanf() function places the value entered by the user at the location, or address, of the variable. This is accomplished by using the & symbol.
&num is the address of variable num.

A memory address is given as a hexadecimal number. Hexadecimal, or hex, is a base-16 number system that uses digits 0 through 9 and letters A through F (16 characters) to represent a group of four binary digits that can have a value from 0 to 15.
It’s much easier to read a hex number that is 8 characters long for 32 bits of memory than to try to decipher 32 1s and 0s in binary.
The following program displays the memory addresses for variables i and k

#include <stdio.h>

void test(int k);

int main() {
    int i = 0;
    
    printf("The address of i is %x\n", &i);
    test(i);
    printf("The address of i is %x\n", &i);
    test(i);

    return 0;
}

void test(int k) {
    printf("The address of k is %x\n", &k);
}

In the printf statement, %x is the hex format specifier.
%p is what should really be used as it returns the address which is already in hexadecimal form preceded by 0x. Using %x casts the pointers hexadecimal value to an unsigned int and then converts that new value to hexadecimal. %u has a similar effect.
Program output varies from run to run, but looks similar to:

The address of i is 846dd754
The address of k is 846dd758
The address of i is 846dd754
The address of k is 846dd758

The address of a variable stays the same from the time it is declared until the end of its scope.

What is a Pointer?

Pointers are very important in C programming because they allow you to easily work with memory locations.
They are fundamental to arrays, strings, and other data structures and algorithms.
A pointer is a variable that contains the address of another variable. In other words, it “points” to the location assigned to a variable and can indirectly access the variable.
Pointers are declared using the * symbol and take the form:

pointer_type *identifier

pointer_type is the type of data the pointer will be pointing to. The actual pointer data type is a hexadecimal number, but when declaring a pointer, you must indicate what type of data it will be pointing to.
Asterisk * declares a pointer and should appear next to the identifier used for the pointer variable.
The following program demonstrates variables, pointers, and addresses:

#include <stdio.h>

int main() {
    int j = 63;
    int *p = NULL;
    p = &j; 
    
    printf("The address of j is %x\n", &j);
    printf("p contains address %x\n", p);
    printf("The value of j is %d\n", j);
    printf("p is pointing to the value %d\n", *p);
}

There are several things to notice about this program:
• Pointers should be initialized to NULL until they are assigned a valid location.
• Pointers can be assigned the address of a variable using the ampersand & sign.
• To see what a pointer is pointing to, use the * again, as in *p. In this case the * is called the indirection or dereference operator. The process is called dereferencing.
The program output is similar to:

The address of j is ff3652cc
p contains address ff3652cc
The value of j is 63
p is pointing to the value 63

Some algorithms use a pointer to a pointer. This type of variable declaration uses **, and can be assigned the address of another pointer, as in:
int x = 12;
int *p = NULL
int **ptr = NULL;
p = &x;
ptr = &p;

Pointers in Expressions

Pointers can be used in expressions just as any variable. Arithmetic operators can be applied to whatever the pointer is pointing to.

#include <stdio.h>

int main() {
    int x = 5;
    int y;
    int *p = NULL;
    p = &x;
    
    y = *p + 2; /* y is assigned 7 */
    y += *p;     /* y is assigned 12 */
    *p = y;       /* x is assigned 12 */
    (*p)++;      /* x is incremented to 13 */

    printf("p is pointing to the value %d\n", *p); 
}

Note that parentheses are required for the ++ operator to increment the value being pointed to. The same is true when using the – operator.

More On Pointers

Pointers and Arrays

Pointers are especially useful with arrays. An array declaration reserves a block of contiguous memory addresses for its elements. With pointers, we can point to the first element and then use address arithmetic to traverse the array:
+ is used to move forward to a memory location
- is used to move backward to a memory location

#include <stdio.h>

int main() {
    int a[5] = {22, 33, 44, 55, 66};
    int *ptr = NULL;
    int i;
    
    ptr = a;
    for (i = 0; i < 5; i++) {
        printf("%d ", *(ptr + i));
    }
}

An important concept with arrays is that an array name acts as a pointer to the first element of the array. Therefore, the statement ptr = a can be thought of as ptr = &a[0].
Consider the following statement, which prints the first element of the array: printf("%d ", *a);

More Address Arithmetic

Address arithmetic can also be thought of as pointer arithmetic because the operations involve pointers.
Besides using + and – to refer to the next and previous memory locations, you can use the assignment operators to change the address the pointer contains.

#include <stdio.h>

int main() {
    int a[5] = {22, 33, 44, 55, 66};
    int *ptr = NULL;
        
    ptr = a;  /* point to the first array element */
    printf("%d  %x\n", *ptr, ptr);  /* 22 */
    ptr++;
    printf("%d  %x\n", *ptr, ptr);  /* 33 */
    ptr += 3;
    printf("%d  %x\n", *ptr, ptr);  /* 66 */
    ptr--;
    printf("%d  %x\n", *ptr, ptr);  /* 55 */
    ptr -= 2;
    printf("%d  %x\n", *ptr, ptr);  /* 33 */ 
}

Program output is similar to:

22 febd4760
33 febd4764
66 febd4770
55 febd476c
33 febd4764

When a pointer is incremented, the memory address increases by the number of bytes being pointed to. In the program above, the pointer increases by 4 when the increment operator is used (ptr++) because the pointer is pointing to an int.
You can also use the ==, <, and > operators to compare pointer addresses.

Pointers and Functions

Pointers greatly expand the possibilities for functions. No longer are we limited to returning one value. With pointer parameters, your functions can alter(change) actual data rather than a copy of data.
To change the actual values of variables, the calling statement passes addresses to pointer parameters in a function.
For example, the following program swaps two values:

#include <stdio.h>

void swap (int *num1, int *num2);

int main() {
    int x = 25;
    int y = 100;

    printf("x is %d, y is %d\n", x, y); 
    swap(&x, &y);
    printf("x is %d, y is %d\n", x, y); 

    return 0;
}
 
void swap (int *num1, int *num2) {
    int temp;
    
    temp = *num1;
    *num1 = *num2;
    *num2 = temp;
}

The program swaps the actual values of the variables, as the function accesses them by address using pointers.

Functions & Arrays

Functions with Array Parameters

An array cannot be passed by value to a function. However, an array name is a pointer, so just passing an array name to a function is passing a pointer to the array.

#include <stdio.h>

int add_up (int *a, int num_elements);

int main() {
    int orders[5] = {100, 220, 37, 16, 98};

    printf("Total orders is %d\n", add_up(orders, 5)); 

    return 0;
}

int add_up (int *a, int num_elements) {
   int total = 0;
   int k;

   for (k = 0; k < num_elements; k++) {
        total += a[k];
   }

    return (total);
}

Program output is: “Total orders is 471”

Functions that Return an Array

Just as a pointer to an array can be passed into a function, a pointer to an array can be returned, as in the following program:

#include <stdio.h>

int * get_evens();

int main() {
    int *a;
    int k;

    a = get_evens(); /* get first 5 even numbers */
    for (k = 0; k < 5; k++)
      printf("%d\n", a[k]); 

    return 0;
}

int * get_evens () {
   static int nums[5];
   int k;
   int even = 0;

   for (k = 0; k < 5; k++) {
        nums[k] = even += 2; /* 右结合性,从右到左 */
   }

    return (nums);
}

Note that a pointer, not an array, is declared to store the value returned by the function. Also note that when a local variable is being passed out of a function, you need to declare it as static in the function.
Keep in mind that a[k] is the same as *(a + k).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值