מצביעים וכתובות מבוא כללי למדעי המחשב

Slides:



Advertisements
Similar presentations
 A string is an array of characters.  Strings must have a 0 or null character after the last character to show where the string ends.  The null character.
Advertisements

Array_strcpy void array_strcpy(char dest[], char src[]) { int i = 0; while (src[i] != '\0') { dest[i] = src[i]; i++; } dest[i] = '\0'; }
Sort the given string, without using string handling functions.
Pointers Discussion 5 Section Housekeeping HW 1 Issues Array Issues Exam 1 Questions? Submitting on Time!
1 CSE1301 Computer Programming Lecture 16 Pointers.
CSSE 332 Explicit Memory Allocation, Parameter passing, and GDB.
Overview Pointer Variables Pass by Value Pass by Reference (or by Pointer) Arrays.
Pointers Example Use int main() { int *x; int y; int z; y = 10; x = &y; y = 11; *x = 12; z = 15; x = &z; *x = 5; z = 8; printf(“%d %d %d\n”, *x, y, z);
1 CSE1301 Computer Programming Lecture 16 Pointers.
C Programming Strings. Array of characters – most common type of array in C  Let’s make them easier for use Denote the end of array using a special character.
Programming Pointers. Variables in Memory x i c The compiler determines where variables are placed in memory This placement cannot.
CMPE-013/L: “C” Programming Gabriel Hugh Elkaim – Spring 2013 CMPE-013/L Arrays and Strings Gabriel Hugh Elkaim Spring 2013.
Pointers CSE 2451 Rong Shi.
 Review structures  Program to demonstrate a structure containing a pointer.
Lecture 10 Introduction to Programming in C Prof. Dr. Arne Kutzner Hanyang University / Seoul Korea.
Xuan Guo Review for the Final Exam Xuan Guo July 29 8:30AM – 10:30AM Classroom South 300 CSC
Functions & Pointers in C Jordan Erenrich
Pointers and Arrays An array's name is a constant whose value is the address of the array's first element. For this reason, the value of an array's name.
Pointers PART - 2. Pointers Pointers are variables that contain memory addresses as their values. A variable name directly references a value. A pointer.
Chapter 1 Basic C Programming
2/23/2016Course material created by D. Woit 1 CPS 393 Introduction to Unix and C START OF WEEK 9 (C-3)
 Memory setup  Pointer declaration  Address operator  Indirection  Printing addresses or pointers.
POINTERS IN C Pointer Basics, Pointer Arithmetic, Pointer to arrays and Pointer in functions.
Dr. Sajib Datta Feb 21,  In the last class we discussed: ◦ Bubble sort  How it works  performance.
Array Sort. Sort Pass 1 Sort Pass 2 Sort Pass 3.
 Recursion  Pointers and Arrays #include void print3(int n){ if (n==0)return; printf ("%d\n",n); print3(n-1); printf ("%d\n",n); } void main(){ print3(5);
1 Memory, Arrays & Pointers. Memory 2 int main() { char c; int i,j; double x; cijx.
Arrays Name, Index, Address. Arrays – Declaration and Initialization int x; y[0] y[1] y[2]
Arrays and Pointers (part 1) CSE 2031 Fall July 2016.
C language--Introduction. History 1970: B by Ken Thompson at AT&T Bell Lab 1972: C by Dennis Ritchie and Ken Tompson at At&T Bell Lab for UNIX 1978: “The.
CISC220 Spring 2010 James Atlas Lecture 04: Pointers, Functions, Memory Management, ADTs, Classes, Hardware, Software, Graphics, Networking, AI, Databases,
Introduction to Computer Algorithmics and Programming Ceng 113 Serap ATAY Pointers _ Part 2.
מערכים (arrays) 02 אוקטובר אוקטובר אוקטובר 1602 אוקטובר אוקטובר אוקטובר 1602 אוקטובר אוקטובר אוקטובר 16 Department.
INC 161 , CPE 100 Computer Programming
Pointers & Arrays 1-d arrays & pointers 2-d arrays & pointers.
“Studying C programming excluding pointers is meaningless.” d0m3z
CSE 220 – C Programming Pointers.
Lecture 8 String 1. Concept of strings String and pointers
Quiz 11/15/16 – C functions, arrays and strings
Pointers Department of Computer Science-BGU יום שלישי 31 יולי 2018.
C programming language
INC 161 , CPE 100 Computer Programming
Module 2 Arrays and strings – example programs.
CSI-121 Structured Programming Language Lecture 16 Pointers
מצביעים, הקצאה דינאמית ומבנים
מחרוזות קרן כליף.
Dynamic memory allocation and Intraprogram Communication
Introduction to Programming in C
הרצאה 6: כתובות ומצביעים הקצאה דינמית מחרוזות
Object-Oriented Programming (OOP) Lecture No. 36
Pointers Department of Computer Science-BGU יום רביעי 21 נובמבר 2018.
Pointers  Week 10.
Computer Programming תרגול 9 Summer 2016
Pointers and dynamic memory
بنام خدا زبان برنامه نویسی C (21814( Lecture 11 Pointers
כתיבת מאקרו הפקודה assert מצביעים לפונקציות
Outline Defining and using Pointers Operations on pointers
Introduction to Problem Solving and Programming
C Strings Prabhat Kumar Padhy
Exercise Arrays.
Strings Adapted from Dr. Mary Eberlein, UT Austin.
Strings in C Array of characters is called a string.
Character Arrays char string1[] = “first”;
Strings #include <stdio.h>
Programming Strings.
Strings Adapted from Dr. Mary Eberlein, UT Austin.
Dynamic Memory – A Review
Arrays and Pointers CSE 2031 Fall July 2019.
FUNCTION ||.
컴퓨터 프로그래밍 기초 - 13th : 마지막 수업 -
Presentation transcript:

מצביעים וכתובות מבוא כללי למדעי המחשב www.cs.tau.ac.il/courses/cs4math/10b

נקודה לתשומת-לב: הגרשיים תו קבוע מסויים רושמים בתוך גרש בודדת. למשל: ‘a’ או ‘?’ מחרוזת קבועה מסויימת רושמים בתוך גרשיים כפולים. למשל: “HELLO” אם רושמים “a” אז המשמעות היא מחרוזת שיש בה את התו ‘a’ ואחריו את התו ‘\0’. כלומר זה שונה מאשר לרשום ‘a’. אז כשעושים פעולות על מחרוזות צריך להקפיד על גרשיים כפולים, למשל: strcmp(input,”a”) ולא: strcmp(input,’a’) ‘a’'0\'

מחרוזות – נקודה לתשומת-לב כשמכניסים למחרוזת ערך ע"י פעולה על מחרוזת שלמה, אז תו-הסיום '0\' מוכנס אוטומטית אחרי תווי המחרוזת (בלי שרושמים אותו במפורש). למשל: char str[ ]=“Hello”; scanf(“%s”, str); scanf(“%40s”, str); gets(str); אם מכניסים למחרוזת תו-תו, לא ע"י פעולה על מחרוזת שלמה, אז צריך להוסיף במפורש את תו-הסיום כדי לעשות לאחר-מכן פעולות על המחרוזת בשלמותה. למשל: char str[ ]={‘H’,’e’,’l’,’l’,’o’,’\0’};

מחרוזות – עוד נקודה לתשומת-לב זיכרו שה- Enter שמוכנס בסיום הקלט נשאר בזיכרון-הקלט של המחשב. כלומר אם נקלוט תו אחרי שקלטנו מחרוזת אז הוא יכיל את ‘\n’ (ולא נתבקש לרשום תו נוסף): scanf(“%s”, str); abcd scanf(“%c”, &tav); כמו שראינו בעבר, ניתן להתגבר על כך ע"י זה שנגיד לפקודת-הקלט הבאה לדלג על ‘\n’: scanf(“\n%c”, &tav); e

נושאי השיעור היום: כתובות ומצביעים מהן כתובות בזיכרון פעולות עם כתובות מהם מצביעים ומה אפשר לעשות איתם

כתובות בזיכרון אמרנו בעבר שהזיכרון של המחשב מורכב מתאים (בתים) רבים. במחשבים הנוכחיים מדובר במיליונים ואפילו מיליארדים. לכל תא בזיכרון יש כתובת (מספר תא). כל משתנה נשמר בזיכרון החל מכתובת מסויימת (הוא יכול לתפוס יותר מתא אחד, בהתאם לטיפוס המשתנה). למשל, כשמגדירים משתנה על-ידי: int i; המחשב מקצה עבור המשתנה i מקום בזיכרון בכתובת שהוא בוחר. הוא שומר טבלה של כתובות המשתנים.

כתובות בזיכרון - דוגמא התוכנית הזיכרון טבלת הכתובות int main() { int i; } משתנה כתובת ? i 7500 7500 כתובת כלשהי שהמחשב בחר כתובת כלשהי שהמחשב בחר

כתובות בזיכרון - דוגמא התוכנית הזיכרון טבלת הכתובות int main() { int i; i=10; } משתנה כתובת 10 i 7500 7500 ערך המשתנה מתעדכן בזיכרון

כתובות בזיכרון - דוגמא התוכנית הזיכרון טבלת הכתובות int main() { int i=10; } משתנה כתובת 10 i 7500 7500 אותו דבר אם הערך ניתן באיתחול

כתובות בזיכרון - דוגמא התוכנית הזיכרון טבלת הכתובות int main() { int i=10; char c=‘A’; } 10 משתנה כתובת 7500 i 7500 c 9200 ‘A’ 9200 כך גם עבור משתנים מסוגים אחרים

כתובות בזיכרון - דוגמא התוכנית הזיכרון טבלת הכתובות int main() { int i=10; char c=‘A’; } 10 משתנה כתובת 7500 i 7500 c 9200 65 9200 כזכור, למעשה נשמר ערך האסקי של התו

כתובות בזיכרון – גודל המשתנה בטבלת הכתובות נשמר נתון נוסף, שהוא מספר התאים (בתים) שמשמשים ליצוג המשתנה הזה. למשל, char מיוצג על-ידי בית אחד, int על-ידי ארבעה, ועבור double שמונה (ברוב הקומפיילרים). כשאנחנו מתייחסים בתוכנית לשם של משתנה, המחשב בודק בטבלה איפה המשתנה הזה נמצא בזיכרון וכמה מקום הוא תופס, וכך הוא יודע להביא לנו את הערך שלו.

כתובות בזיכרון - דוגמא התוכנית הזיכרון טבלת הכתובות int main() { int i=10; char c=‘A’; } משתנה כתובת גודל 10 i 7500 4 c 92001 7500 65 9200 המחשב מקצה 4 תאים (בתים). intעבור אם המספר קטן אז הספרות הראשונות יהיו מאופסות.

כתובות – איך מתייחסים אליהן שפת C מאפשרת לנו לדעת מהי הכתובת בזיכרון שבה נשמר משתנה מסויים. הפעולה & נותנת את הכתובת של המשתנה. למשל &i היא הכתובת בזיכרון של המשתנה i. בדוגמא הקודמת &i נותן 7500.

כתובות בזיכרון - דוגמא התוכנית הזיכרון טבלת הכתובות int main() { int i=10; } משתנה כתובת גודל 10 i 7500 4 7500 &i זה 7500

כתובות – איך ניגשים אליהן אמרנו שהפעולה & נותנת את הכתובת של משתנה. למשל &i היא הכתובת בזיכרון של המשתנה i. בדוגמא הקודמת &i היה נותן 7500. הפעולה * ניגשת לערך שנמצא בכתובת מסויימת. למשל *(4000) זה הערך שנמצא בכתובת 0040. *(&c) זה הערך של המשתנה c (כי זה הערך שנמצא בכתובת של(c .

כתובות בזיכרון - דוגמא התוכנית הזיכרון טבלת הכתובות int main() { char c=‘A’; } משתנה כתובת 65 c 9200 9200 *(9200) זה 65

כתובות – מה אפשר לעשות איתן לא ניתן לשנות כתובת של משתנה. כלומר לא ניתן לכתוב למשל: &i=5000. ניתן לשנות את הערך שנמצא בכתובת מסויימת. למשל: *(&c)=‘A’;. זה כמו לכתוב c=‘A’;. מסוכן לשנות את הערך שנמצא בכתובת כלשהי שאיננה כתובת של משתנה. למשל *(4000)=123;. אנחנו עלולים לשנות מקום בזיכרון ששייך למערכת ההפעלה, ולגרום לתוכנית לעוף. לכן נשנה רק ערכים של משתנים שהגדרנו.

בשביל מה כל זה טוב? הרי כדי לשנות ערך של משתנה אפשר פשוט לשים בו ערך. למשל i=10;. אז בשביל מה נירצה לדעת מה הכתובת שלו? למה שנירצה לשים ערך בכתובת מסויימת ולא להשתמש פשוט בשם המשתנה?

בשביל מה נשתמש בכתובות אמרנו שכל משתנה מוכר רק בתוך הפונקציה שהוא הוגדר בה. נשתמש בכתובות כדי לשנות ערך של משתנה מתוך פונקציה אחרת, שהוא לא הוגדר בה. בפרט, אם רוצים שפונקציה תשנה כמה משתנים (ולא רק תחזיר ערך אחד), אז אפשר להעביר אליה את הכתובות שלהם. זה מאפשר לה לשנות באופן ישיר את ערכיהם בזיכרון.

דוגמא שהכרנו השתמשנו בהעברת כתובת בפונקציה scanf, שמקבלת את כתובת המשתנה שאליו יוכנס הקלט. למשל: int grade; scanf(“%d”, &grade); המשתנה grade לא מוגדר בפונקציה scanf והיא גם לא מחזירה לתוכו ערך. הפונקציה scanf מקבלת את הכתובת של המשתנה בזיכרון, וזה מאפשר לה לכתוב לתוכו את הקלט (בעזרת הפעולה * שהכרנו קודם). קידוד הקלט (למשל %d) אומר ל- scanf גם מה גודל המשתנה הזה בזיכרון, כלומר לכמה תאים הקלט אמור להיכנס.

כתובות בזיכרון - פעולות מציאת הכתובת של משתנה עם הפעולה & גישה לערך של משתנה לפי כתובתו עם הפעולה * זה יאפשר לנו לשנות יותר ממשתנה אחד בפונקציה שאלות?

עבודה עם כתובות - מצביעים יש ב-C טיפוסי-משתנים לשמירת כתובות בזיכרון. הם נקראים "מצביעים" או "פויינטרים". אפשר להגדיר למשל: char *my_pointer; int *pointer1; באופן כללי, כדי להגדיר משתנה מסוג מצביע, רושמים את סוג המשתנה שעליו מצביעים, וכותבים * לפני שם המשתנה. עוד דוגמאות: double *my_pointer1; float *ptr; char משתנה לשמירת כתובת של int משתנה לשמירת כתובת של

עבודה עם כתובות - מצביעים יש ב-C טיפוסי-משתנים לשמירת כתובות בזיכרון. הם נקראים "מצביעים" או "פויינטרים". אפשר להגדיר למשל: char *my_pointer; int *pointer1; באופן כללי, כדי להגדיר משתנה מסוג מצביע, רושמים את סוג המשתנה שעליו מצביעים, וכותבים * לפני שם המשתנה. שימו לב שזה שימוש אחר בכוכבית (להגדרת משתנה מטיפוס מצביע), נוסף לשימוש שראינו קודם (לגישה לערך בכתובת). char משתנה לשמירת כתובת של int משתנה לשמירת כתובת של

מצביעים – משמעות מצביע מכיל למעשה הפניה ("חץ") למשתנה אחר. לדוגמא: int i=10; int *my_pointer; my_pointer = &i; int הגדרת מצביע לשמירת כתובת של iמוכנסת אליו הכתובת בזיכרון של המשתנה 10 i my_pointer כתובת 300 (לדוגמא) 300

גישה למשתנה על-ידי מצביע כאמור, כדי להתייחס לערך שנמצא בכתובת מסויימת, משתמשים בסימן *. ניראה קטע תוכנית שמדגים את זה: int i=10; int *my_pointer; my_pointer = &i; *my_pointer = 100; printf(“The value of i is now %d”, i); intהגדרת מצביע על iשמים במצביע את כתובת המשתנה שמים 100 במקום שהפויינטר מצביע עליו יודפס המספר 100 100 i my_pointer_to_int

למה יש מצביע שונה לכל טיפוס? סוג המצביע אומר מה גודל המשתנה שמצביעים עליו, ואיך רוצים להתייחס לתוכן הכתובת הזאת (למשל שלם או ממשי). אז כשמתייחסים לערך שעליו מצביעים, המחשב יודע בכמה בתים הוא מיוצג ואיך, ומביא/מאחסן את הערך הנכון. ניראה בעתיד איך זה מאפשר גם לעשות "חישובי-כתובות". אם נירצה לגשת ל- int שנמצא בזיכרון מייד אחרי i, אז נוכל להוסיף 1 למצביע על i, והמחשב ידע בכמה בתים להתקדם בהתאם לגודל של int

מצביעים וכתובות – נקודות לתשומת-לב נשים לב שלקבועים וביטויים אין כתובת. למשל, לא נכתוב: &5 &(i*2) רק למשתנים יש כתובת. כיוון שלא ניתן לשנות כתובת של משתנה (המחשב קובע אותה), לא ניתן לבצע עליה השמה: &a=&b.

מצביעים – דוגמא נתאר פונקציה שמקבלת כתובות של שני משתנים מסוג int, ומחליפה בין הערכים שלהם. (עד עכשיו לא יכולנו לכתוב פונקציה להחלפת ערכים של שני משתנים מסוג int, כי שינוי משתנים מסוג int בפונקציה לא משפיע על ערכם המקורי, ופונקציה יכולה להחזיר רק ערך אחד). void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } השימוש למשל על-ידי: swap(&i, &j); first ערך המשתנה שכתובתו הועברה אל יוחלף עם ערך המשתנה שכתובתו הועברה אל second

דוגמא: פונקציה להחלפה בין ערכי משתנים void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } int main() int i=10, j=20; swap(&i,&j);

דוגמא: פונקציה להחלפה בין ערכי משתנים void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } int main() int i=10, j=20; swap(&i,&j);

דוגמא: פונקציה להחלפה בין ערכי משתנים void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } int main() int i=10, j=20; swap(&i,&j); 10 i 20 j

דוגמא: פונקציה להחלפה בין ערכי משתנים void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } int main() int i=10, j=20; swap(&i,&j); first second 10 i 20 j

דוגמא: פונקציה להחלפה בין ערכי משתנים void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } int main() int i=10, j=20; swap(&i,&j); first second temp 10 i 20 j

דוגמא: פונקציה להחלפה בין ערכי משתנים void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } int main() int i=10, j=20; swap(&i,&j); first second temp 10 10 i 20 j

דוגמא: פונקציה להחלפה בין ערכי משתנים void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } int main() int i=10, j=20; swap(&i,&j); first second temp 10 20 i 20 j

דוגמא: פונקציה להחלפה בין ערכי משתנים void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } int main() int i=10, j=20; swap(&i,&j); first second temp 10 20 i 10 j

דוגמא: פונקציה להחלפה בין ערכי משתנים void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } int main() int i=10, j=20; swap(&i,&j); 20 i 10 j

דוגמא: פונקציה להחלפה בין ערכי משתנים void swap(int *first, int *second) { int temp; temp=*first; *first=*second; *second=temp; } int main() int i=10, j=20; swap(&i,&j); בלי מצביעים לא יכולנו לשנות יותר ממשתנה אחד על-ידי פונקציה 20 i 10 j

עוד על פונקציות ומצביעים פונקציה יכולה להחזיר מצביע (כלומר כתובת של משתנה). אבל לא נחזיר כתובת של משתנה שהוגדר בתוך הפונקציה, כי אחרי שהפונקציה מסתיימת המשתנה כבר לא נמצא שם (גישה לשם תגרום לתעופה).

עוד על פונקציות ומצביעים למשל: int *address_of _the_higher_number(int *a, int*b) { if(*a > *b) return a; return b; }

עוד על פונקציות ומצביעים למשל: int *address_of _the_higher_number(int *a, int*b) { if(*a > *b) return a; return b; } int main() { int *ptr, i=10, j=0; ptr = address_of _the_higher_number(&i, &j); return 0; מוחזרת כתובת המשתנה שמכיל את הערך הגדול יותר מבין השניים והשימוש ניראה כך למשל:

עוד על פונקציות ומצביעים אמרנו שהערך שמוחזר מפונקציה יכול להיות מצביע: int *address_of _the_higher_number(int *a, int*b); אבל החזרת כתובת משתנה שהוגדר בתוך הפונקציה תגרום לשגיאה. כי המשתנים שמוגדרים בתוך הפונקציה נעלמים עם סיומה. למשל הפונקציה הבאה תגרום לשגיאה: int *give_pointer_to_zero() { int i=0; return &i; } i

מצביעים ומערכים הגדרת מערך מקצה בזיכרון מקומות רצופים עבור התאים שלו. בנוסף, מוקצה משתנה ששמו הוא שם-המערך, שמכיל את כתובת התא הראשון של המערך (לא ניתן לשנות את ערכו). לכן אפשר לגשת לתאי מערך גם ע"י חישוב הכתובת שלהם. למשל *(array+5) שקול ל- array[5]. המחשב יודע לאיזה כתובת לגשת כשעושים את החשבון הזה, כי הוא יודע כמה מקום תופס כל תא במערך לפי הטיפוס. array[0] array[9] . כתובת 500 (למשל) 500 array

העברת מערך לפונקציה (האמת...) כאשר מועבר מערך לפונקציה, בעצם מועבר מצביע למערך זו הסיבה שאין צורך לכתוב את גודל המערך בהגדרת הפונקציה. לדוגמא int calc_sum(int my_array[100], int size) שקול ל int calc_sum(int *my_array, int size)

מצביעים ומערכים אי-אפשר לשנות כתובת של מערך (היא נקבעת כשהוא מוגדר). לכן לא ניתן לכתוב array=array1, או array=0. אפשר לשים כתובת של מערך בתוך מצביע. אפשר לכתוב: char *array_ptr; array_ptr=array; (השורה האחרונה שקולה לשורה:array_ptr = &array[0]; ) כלומר, משתנה מערך הוא סוג של מצביע (אבל לא להיפך). מערך הוא למעשה מצביע שמקבל כתובת בהגדרה ולא ניתן לשנות אותה. (שמים במצביע את כתובת התא הראשון במערך)

גישה לתאי-מערך לפי הכתובת אם הגדרנו למשל: int array[10]; int *array_ptr; array_ptr=array; אז אפשר לגשת לתאי-המערך גם לפי הכתובת שלהם, כמו משתנים אחרים. 3 הפעולות הבאות עושות אותו דבר (שמות 100 בתא מס' 5 במערך): array[5]=100; *(array+5)=100; *(array_ptr+5)=100; - המחשב יודע כמה בתים להתקדם כשאנחנו מבקשים להתקדם ב-5 תאים קדימה, כי הגדרנו שטיפוס הערכים הוא int והוא יודע כמה בתים כל int תופס (כאמור, ערכי המערך שמורים בזיכרון ברצף). (מצביע על התא הראשון במערך) גישה לתא שנמצא 5 תאים אחרי התא הראשון

גישה למערך לפי כתובת – דוגמא נוספת נאמר שמוגדרים: int i,array[10]={0}; int *ptr; אז 3 הקטעים הבאים עושים בדיוק אותו דבר (מדפיסים את המערך): for (i=0; i<10; i++) printf(“%d ”, array[i]); printf(“%d ”, *(array+i)); for (ptr=array; ptr <= &array[9]; ptr++) printf(“%d ”, *ptr); 1) הדפסה על-ידי גישה רגילה לתאי המערך 2) הדפסה על-ידי גישה לכל תא לפי הכתובת שלו יחסית לתא הראשון 3) הדפסה ע"י קידום מצביע מכתובת התא הראשון עד כתובת התא האחרון

מערכים ופונקציות - הסבר אמרנו בעבר שכשמעבירים מערך לפונקציה שינויים שנעשה בפונקציה ישפיעו על המערך המקורי. זה נובע מכך שלפונקציה מועברת הכתובת בזיכרון של המערך המקורי, והיא פועלת ישירות על ערכיו (ולא על העתק שלהם). למשל, כפי שאמרנו, הפונקציה הבאה תאפס מערך שמועבר אליה: void zero_array(int a[ ], int size) { int i; for(i=0 ; i<size; i++) a[i]=0; }

מערכים ופונקציות - הסבר אמרנו בעבר שכשמעבירים מערך לפונקציה שינויים שנעשה בפונקציה ישפיעו על המערך המקורי. זה נובע מכך שלפונקציה מועברת הכתובת בזיכרון של המערך המקורי, והיא פועלת ישירות על ערכיו (ולא על העתק שלהם). למשל, כפי שאמרנו, הפונקציה הבאה תאפס מערך שמועבר אליה: void zero_array(int *a, int size) { int i; for(i=0 ; i<size; i++) a[i]=0; } נציין שאם פונקציה מצפה לקבל מצביע, אפשר להעביר אליה מערך מהסוג הזה, כי בשני המקרים מה שמועבר הוא כתובת בזיכרון.

מערכים ופונקציות למשל הפונקציות שהזכרנו על מחרוזות (כמו strcmp, strlen) מוגדרות למעשה עבור מצביעים מסוג char *. באחריותנו להפעיל אותן באמת על מחרוזת (כלומר רצף תווים שמסתיים ב- '0\') ולא סתם על מצביע לתו או מערך של תווים (נקבל תוצאות שגויות אם אין את תו הסיום). כמו-כן, כזכור, אם פונקציה מוגדרת על מערך בגודל מסויים, ניתן להעביר אליה גם מערך בגודל אחר של אותו טיפוס (כי כאמור מה שמועבר זה רק כתובת ההתחלה). שוב, זה באחריותנו שתתבצע בפונקציה פעולה הגיונית ושהיא תדע מה גודל המערך ולא תחרוג ממנו.

"מצביע על כלום" לפעמים נירצה לסמן שמצביע לא מצביע לשום משתנה (למשל לפני שהתחלנו להשתמש בו). מקובל לעשות זאת ע"י זה שנכניס אליו את הכתובת 0 (שאיננה כתובת אפשרית של משתנה מטיפוס כתובת). למעשה, במקום לרשום 0 מקובל לרשום NULL. זהו קבוע שערכו 0, שמוגדר ע"י #define בספריה stdlib.h. למשל: #include<stdlib.h> int *ptr=NULL; לא לבלבל בין הכתובת NULL לבין תו סיום מחרוזת ‘\0’

דוגמא: חיפוש תו במחרוזת #include<stdlib.h> char *my_strchr(char *str, char tav) { while((*str != ‘\0’) && (*str != tav)) str++; if (*str == tav) return str; return NULL } מקבלת מצביע לתחילת מחרוזת ותו מתקדמים עד שמצאנו את התו או הגענו לסוף המחרוזת אם מצאנו מוחזר מצביע להופעה הראשונה אם לא מצאנו מחזירים NULL