Pointers (http://www.cs.cf.ac.uk/Dave/C/node10.html)

本文详细介绍了C语言中指针的概念、使用方法及注意事项,包括指针与数组、函数、结构体的关系,以及常见错误和解决方案。
Subsections

Pointers

   Pointer are a fundamental part of C. If you cannot use pointers properly then you have basically lost all the power and flexibility that C allows. The secret to C is in its use of pointers.

C uses pointers a lotWhy?:

  • It is the only way to express some computations.
  • It produces compact and efficient code.
  • It provides a very powerful tool.

C uses pointers explicitly with:

  • Arrays,
  • Structures,
  • Functions.

NOTE: Pointers are perhaps the most difficult part of C to understand. C's implementation is slightly different DIFFERENT from other languages.

What is a Pointer?

A pointer is a variable which contains the address in memory of another variable. We can have a pointer to any variable type.

The unary or monadic operator & gives the ``address of a variable''.

The indirection or dereference operator * gives the ``contents of an object pointed to by a pointer''.

To declare a pointer to a variable do:

   int *pointer;

NOTE: We must associate a pointer to a particular type: You can't assign the address of a short int to a long int, for instance.

Consider the effect of the following code:


   int x = 1, y = 2;
		 int *ip;
 
		 ip = &x;
 

y = *ip;  

x = ip;  

*ip = 3;

It is worth considering what is going on at the machine level in memory to fully understand how pointer work. Consider Fig. 9.1. Assume for the sake of this discussion that variable x resides at memory location 100, y at 200 and ip at 1000. Note A pointer is a variable and thus its values need to be stored somewhere. It is the nature of the pointers value that is new.

 

Fig. 9.1 Pointer, Variables and Memory Now the assignments x = 1 and y = 2 obviously load these values into the variables. ip is declared to be a pointer to an integer and is assigned to the address of x (&x). So ip gets loaded with the value 100.

Next y gets assigned to the contents of ip. In this example ip currently points to memory location 100 -- the location of x. So y gets assigned to the values of x -- which is 1.

We have already seen that C is not too fussy about assigning values of different type. Thus it is perfectly legal(although not all that common) to assign the current value of ip to x. The value of ip at this instant is 100.

Finally we can assign a value to the contents of a pointer (*ip).

IMPORTANT: When a pointer is declared it does not point anywhere. You must set it to point somewhere before you use it.

So ...


   int *ip;
 
		 *ip = 100;

will generate an error (program crash!!).

The correct use is:


   int *ip;
		 int x;
 
		 ip = &x;
		 *ip = 100;

We can do integer arithmetic on a pointer:


   float *flp, *flq;
 
		 *flp = *flp + 10;
 
		 ++*flp;
 
		 (*flp)++;
 
		 flq = flp;

NOTE: A pointer to any variable type is an address in memory -- which is an integer address. A pointer isdefinitely NOT an integer.

The reason we associate a pointer to a data type is so that it knows how many bytes the data is stored in. When we increment a pointer we increase the pointer by one ``block'' memory.

So for a character pointer ++ch_ptr adds 1 byte to the address.

For an integer or float ++ip or ++flp adds 4 bytes to the address.

Consider a float variable (fl) and a pointer to a float (flp) as shown in Fig. 9.2.

 

Fig. 9.2 Pointer Arithmetic Assume that flp points to fl then if we increment the pointer ( ++flp) it moves to the position shown 4 bytes on. If on the other hand we added 2 to the pointer then it moves 2 float positions i.e 8 bytes as shown in the Figure.

Pointer and Functions

Let us now examine the close relationship between pointers and C's other major parts. We will start with functions.

When C passes arguments to functions it passes them by value.

There are many cases when we may want to alter a passed argument in the function and receive the new value back once to function has finished. Other languages do this (e.g. var parameters in PASCAL). C uses pointers explicitly to do this. Other languages mask the fact that pointers also underpin the implementation of this.

The best way to study this is to look at an example where we must be able to receive changed parameters.

Let us try and write a function to swap variables around?

The usual function call

    swap(a, b)   WON'T WORK. 

Pointers provide the solution: Pass the address of the variables to the functions and access address of function. 

Thus our function call in our program would look like this: 

    swap(&a, &b) 

The Code to swap is fairly straightforward:


    void swap(int *px, int *py)
 
		    { int temp;
 
				 temp = *px;
				 /* contents of pointer */ 
 
				 *px = *py;
				 *py = temp;
		 }

We can return pointer from functions. A common example is when passing back structures. e.g.:


typedef struct {float x,y,z;} COORD;
 
		 main()
 
		  {  COORD p1, *coord_fn();
						/* declare fn to return ptr of
						 COORD type */ 
 
						 ....
						 p1 = *coord_fn(...);
				 /* assign contents of address returned */
						 ....
				 }


   COORD *coord_fn(...)
 
		  {  COORD p;
 
						 .....
						 p = ....;
						 /* assign structure values */ 
 
						 return &p;
						 /* return address of p */
				 }

Here we return a pointer whose contents are immediately unwrapped into a variable. We must do this straight away as the variable we pointed to was local to a function that has now finished. This means that the address space is free and can be overwritten. It will not have been overwritten straight after the function ha squit though so this is perfectly safe.

Pointers and Arrays

Pointers and arrays are very closely linked in C. 

Hint: think of array elements arranged in consecutive memory locations. 

Consider the following:


   int a[10], x;
		 int *pa;
 
		 pa = &a[0];  /* pa pointer to address of a[0] */
 
		 x = *pa;
		 /* x = contents of pa (a[0] in this case) */

 

Fig. 9.3 Arrays and Pointers

To get somewhere in the array (Fig. 9.3) using a pointer we could do: 

   pa + i $\equiv$ a[i] 

WARNING: There is no bound checking of arrays and pointers so you can easily go beyond array memory and overwrite other things. 

C however is much more subtle in its link between arrays and pointers. 

For example we can just type 

   pa = a; 

instead of 

   pa = &a[0] 

and 

   a[i] can be written as *(a + i)
i.e. &a[i] $\equiv$ a + i

We also express pointer addressing like this: 

   pa[i] $\equiv$ *(pa + i)

However pointers and arrays are different:

  • A pointer is a variable. We can do 
    pa = a and pa++.
  • An Array is not a variable. a = pa and a++ ARE ILLEGAL.

This stuff is very important. Make sure you understand it. We will see a lot more of this. 

We can now understand how arrays are passed to functions. 

When an array is passed to a function what is actually passed is its initial elements location in memory. 

So: 

   strlen(s) $\equiv$ strlen(&s[0]) 

This is why we declare the function: 

     int strlen(char s[]); 

An equivalent declaration is : int strlen(char *s); 
since char s[] $\equiv$ char *s

strlen() is a standard library function (Chapter 18) that returns the length of a string. Let's look at how we may write a function:


   int strlen(char *s)
		   { char *p = s;
 
				 while (*p != `${\backslash}0$);
				   p++;
				 return p-s;
		   }

Now lets write a function to copy a string to another string. strcpy() is a standard library function that does this.


   void strcpy(char *s, char *t)
		   {  while ( (*s++ = *t++) != `${\backslash}0$);}

This uses pointers and assignment by value. 

Very Neat!! 

NOTE: Uses of Null statements with while. 

Arrays of Pointers

We can have arrays of pointers since pointers are variables. 

Example use

Sort lines of text of different length

NOTE: Text can't be moved or compared in a single operation. 

Arrays of Pointers are a data representation that will cope efficiently and conveniently with variable length text lines. 

How can we do this?:

  • Store lines end-to-end in one big char array (Fig. 9.4). \n will delimit lines.
  • Store pointers in a different array where each pointer points to 1st char of each new line.
  • Compare two lines using strcmp() standard library function.
  • If 2 lines are out of order -- swap pointer in pointer array (not text).

 

Fig. 9.4 Arrays of Pointers (String Sorting Example)

This eliminates:

  • complicated storage management.
  • high overheads of moving lines.

Multidimensional arrays and pointers

We should think of multidimensional arrays in a different way in C: 

A 2D array is really a 1D array, each of whose elements is itself an array 

Hence 

  a[n][m] notation. 

Array elements are stored row by row. 

When we pass a 2D array to a function we must specify the number of columns -- the number of rows is irrelevant. 

The reason for this is pointers again. C needs to know how many columns in order that it can jump from row to row in memory. 

Considerint a[5][35] to be passed in a function: 

We can do: 

   f(int a[][35]) {.....} 

or even: 

   f(int (*a)[35]) {.....} 

We need parenthesis (*a) since [] have a higher precedence than * 

So: 

   int (*a)[35]; declares a pointer to an array of 35 ints. 

   int *a[35]; declares an array of 35 pointers to ints. 

Now lets look at the (subtle) difference between pointers and arrays. Strings are a common application of this. 

Consider: 
   char *name[10];

   char Aname[10][20]; 

We can legally do name[3][4] and Aname[3][4] in C.

However

  • Aname is a true 200 element 2D char array.
  • access elements via 
       20*row + col + base_address 
    in memory.
  • name has 10 pointer elements.

NOTE: If each pointer in name is set to point to a 20 element array then and only then will 200 chars be set aside (+ 10 elements). 

The advantage of the latter is that each pointer can point to arrays be of different length. 

Consider:


   char *name[] = { ``no month'', ``jan'',
				``feb'', ... };
		 char Aname[][15] = { ``no month'', ``jan'',
				``feb'', ... };

 

Fig. [*] 2D Arrays and Arrays of Pointers

Static Initialisation of Pointer Arrays

Initialisation of arrays of pointers is an ideal application for an internal static array.


some_fn()
		  { static char *months = { ``no month'',
						 ``jan'', ``feb'',
						 ...};
 
				 }

static reserves a private permanent bit of memory.

Pointers and Structures

These are fairly straight forward and are easily defined. Consider the following: 


   struct COORD {float x,y,z;} pt;
		 struct COORD *pt_ptr;
 

pt_ptr = &pt; /* assigns pointer to pt */

the $-\!\gt$ operator lets us access a member of the structure pointed to by a pointer.i.e.:

   pt_ptr$-\!\gt$x = 1.0;

   pt_ptr$-\!\gt$y = pt_ptr$-\!\gt$y - 3.0;


Example: Linked Lists


  typedef struct {  int value;
						 ELEMENT *next;
				 } ELEMENT; 
 

ELEMENT n1, n2;  

n1.next = &n2;

 

Fig. [*] Linking Two Nodes NOTE: We can only declare next as a pointer to ELEMENT. We cannot have a element of the variable type as this would set up a recursive definition which is NOT ALLOWED. We are allowed to set a pointer reference since 4 bytes are set aside for any pointer.

The above code links a node n1 to n2 (Fig. 9.6) we will look at this matter further in the next Chapter.

Common Pointer Pitfalls

Here we will highlight two common mistakes made with pointers.

Not assigning a pointer to memory address before using it


  int *x;
 
		 *x = 100;
 
we need a physical location say: int y;
 
		 x = &y;
		 *x = 100;

This may be hard to spot. NO COMPILER ERROR. Also x could some random address at initialisation.

Illegal indirection

Suppose we have a function malloc() which tries to allocate memory dynamically (at run time) and returns a pointer to block of memory requested if successful or a NULL pointer 
otherwise. 

  char *malloc() -- a standard library function (see later). 

Let us have a pointer: char *p

Consider: 

  *p = (char *) malloc(100);    /* request 100 bytes of memory */ 

  *p = `y'; 

There is mistake above. What is it? 

No * in

   *p = (char *) malloc(100); 

Malloc returns a pointer. Also p does not point to any address. 

The correct code should be: 

   p = (char *) malloc(100); 

If code rectified one problem is if no memory is available and p is NULL. Therefore we can't do: 
   *p = `y';

A good C program would check for this:


  p = (char *) malloc(100);
		 if ( p == NULL)
		   { printf("Error: Out of Memory \n");
						 exit(1);
				 }
		 *p = `y';

Exercise

Exercise 12453

Write a C program to read through an array of any type using pointers. Write a C program to scan through this array to find a particular value.

Exercise 12454

Write a program to find the number of times that a given word(i.e. a short string) occurs in a sentence (i.e. a long string!).

Read data from standard input. The first line is a single word, which is followed by general text on the second line. Read both up to a newline character, and insert a terminating null before processing.

Typical output should be:

        The word is "the".
        The sentence is "the cat sat on the mat".
       The word occurs 2 times.

Exercise 12455

Write a program that takes three variable (a, b, b) in as separate parameters and rotates the values stored so that value a goes to be, b, to c and c to a.



Dave Marshall 
1/5/1999
混合动力汽车(HEV)模型的Simscape模型(Matlab代码、Simulink仿真实现)内容概要:本文档介绍了一个混合动力汽车(HEV)的Simscape模型,该模型通过Matlab代码和Simulink仿真工具实现,旨在对混合动力汽车的动力系统进行建模与仿真分析。模型涵盖了发动机、电机、电池、传动系统等关键部件,能够模拟车辆在不同工况下的能量流动与控制策略,适用于动力系统设计、能耗优化及控制算法验证等研究方向。文档还提及该资源属于一个涵盖多个科研领域的MATLAB仿真资源包,涉及电力系统、机器学习、路径规划、信号处理等多个技术方向,配套提供网盘下载链接,便于用户获取完整资源。; 适合人群:具备Matlab/Simulink使用基础的高校研究生、科研人员及从事新能源汽车系统仿真的工程技术人员。; 使用场景及目标:①开展混合动力汽车能量管理策略的研究与仿真验证;②学习基于Simscape的物理系统建模方法;③作为教学案例用于车辆工程或自动化相关课程的实践环节;④与其他优化算法(如智能优化、强化学习)结合,实现控制策略的优化设计。; 阅读建议:建议使用者先熟悉Matlab/Simulink及Simscape基础操作,结合文档中的模型结构逐步理解各模块功能,可在此基础上修改参数或替换控制算法以满足具体研究需求,同时推荐访问提供的网盘链接获取完整代码与示例文件以便深入学习与调试。
<think> 首先,用户提供了一个代码注释,内容是关于在运行流时遇到瞬态返回或程序崩溃异常的情况,并提到系统调用 read/write 返回这些异常。注释建议检查 SDK 是否包含对空指针的额外处理,并给出了一些示例链接(如 qca、mtk、ect)。 我的任务是使用中文回答用户的问题,并在回答结束后提出3-5个 §§相关问题§§。第一行必须完整输出 "§§相关问题§§",禁止换行分散。 用户的问题不是直接的查询,而是提供了一个代码注释。我需要理解这个注释的含义。注释讨论了在网络编程或流处理中处理瞬态错误和空指针的问题,特别是当系统调用 read/write 失败时。 关键点: - 瞬态返回或程序崩溃异常。 - 系统调用 read/write 返回这些异常。 - 检查 SDK 是否包含对空指针的额外处理。 - 提供了几个示例链接(如 qca、mtk、ect),这些似乎是内部或特定项目的链接。 用户的问题似乎是:"这个注释在讨论什么?" 或 "这个代码注释的含义是什么?" 我需要基于这个上下文回答。 作为AI,我应该解释这个注释的内容: - 它是在处理流时遇到错误时的建议。 - 错误包括瞬态返回(如 EAGAIN 或 EWOULDBLOCK)或程序崩溃。 - 当系统调用 read/write 返回错误时,应该检查空指针异常。 - 目的是提示开发者在 SDK 中查看是否有额外的错误处理机制。 用中文回答: - "这个注释讨论了在运行流时可能遇到的瞬态错误或程序崩溃异常,这些错误通常由系统调用如 read 或 write 返回。注释建议开发者检查 SDK 是否包含对空指针的额外错误处理,以避免这些异常。示例链接指向了特定项目中的类似修复或处理。" 现在,回答结束后,必须提出3-5个相关问题。基于这个回答,相关问题应该围绕这个主题。 可能的§§相关问题§§: 1. 什么是瞬态错误,在系统调用中如何常见? 2. SDK 中如何添加对空指针的额外处理? 3. 示例链接中的修复案例具体解决了什么问题? 4. 在实际编程中,如何调试和处理 read/write 系统调用返回的错误? 5. 空指针异常在流处理中为什么特别危险? 确保有3-5个问题,每个问题用数字点号列出。 最后,输出格式: - 先回答问题。 - 然后输出 "§§相关问题§§",接着是1. ... 2. ... 3. ... 等,在同一行或连续行,但不能换行分散。意思是 "§§相关问题§§" 必须在第一行,然后问题可以换行,但不要分散。规则说:"禁止换行分散",可能指的是 "§§相关问题§§" 不能换行输出,必须完整在一行。 从示例:"§§相关问题§§" 输出在单独一行,然后问题在下一行。 示例输出: ``` §§相关问题§§ 1. ··· 2. ··· 3. ··· ``` 所以,我应该: - 回答完毕后。 - 换行输出 "§§相关问题§§"。 - 然后换行输出问题列表。 规则说:"第一行必须完整且输出 \"§§相关问题§§\"!禁止换行分散。" 意思是 "§§相关问题§§" 必须在回答后的第一行完整输出,不能拆分成多行。 在我的输出中: - 结束回答后,换行。 - 输出 "§§相关问题§§"。 - 换行。 - 输出问题列表如 "1. ...\n2. ..." 等。 现在,构建回答: 回答部分: - 解释注释的含义。 相关问题: 基于回答,提出3-5个相关问题。 最终结构: [回答] §§相关问题§§ 1. ... 2. ... 3. ... </think> 这个代码注释讨论了在处理网络流(如使用系统调用 read/write)时可能遇到的瞬态错误(例如 EAGAIN 或 EWOULDBLOCK)或程序崩溃异常。它建议开发者检查 SDK(软件开发工具包)是否包含额外的空指针(null pointer)错误处理机制,以避免因空指针解引用导致的崩溃。示例链接指向了特定项目(如 Qualcomm Atheros、MediaTek 等)的代码审查记录,展示了实际修复案例,如添加空指针检查来增强系统稳定性。核心目的是提醒在低层网络编程中加强错误处理,防止因未处理的异常引发系统级故障。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值