网站建设公司建设,建设网站前的目的,竞价托管代运营多少钱,鱼爪商标交易平台C/C中#xff0c;函数内部的一切变量(函数内部局部变量#xff0c;形参)都是在其被调用时才被分配内存单元。形参和函数内部的局部变量的生命期和作用域都是在函数内部(static变量的生命期除外)。子函数运行结束时#xff0c;所有局部变量的内存单元会被系统释放。在C中中函数内部的一切变量(函数内部局部变量形参)都是在其被调用时才被分配内存单元。形参和函数内部的局部变量的生命期和作用域都是在函数内部(static变量的生命期除外)。子函数运行结束时所有局部变量的内存单元会被系统释放。在C中函数被调用时的传参方式有两种形式传值和传址。 传址的好处 (1) 能在函数内部通过实参地址间接地改变实参的值。 (2) 当所传实参内容比较庞大时传址只是复制了整个实参的地址过去指针依据同一个地址访问实参变量。而传值就会将实参内容整个拷贝过去形参会跟实参占一样大的内存栈空间是有限的。当然了在弱小的程序中传址的这个优点不会被体现出来。 在函数中可以随意的返回一个局部变量。 但如果返回一个局部变量的地址指针编译器就会给出警告。因为函数只是把指针复制后返回了但是指针指向的内容已经被释放这样指针指向的内容就是不可预料的内容程序就会出错。 准确的来说函数不能返回指向栈内存的指针(返回指向堆内存的指针是可以的)。
返回局部变量 C中函数是可以返回局部变量的原因返回值是拷贝值局部变量的作用域为函数内部函数执行结束栈上的局部变量会销毁内存释放。
可返回的局部变量
1、返回局部变量本身
#include iostreamint display() {int num 9;return num;
}int main() {int p display();std::cout p std::endl; // 9return 0;
} display 函数返回一个 int 类型的局部变量 num函数会把局部的num的值复制一份拷贝给主函数里面的 p 变量。这样是可以的而且这种方式在程序里面还是经常用到的。 上面程序输出9
返回局部变量地址 引用一位博主的分析https://blog.csdn.net/qq_34801642/article/details/88411252 C/C语言函数是不能返回局部变量地址特指存放于栈区的局部变量地址除非是局部静态变量地址字符串常量地址、动态分配地址。其原因是一般局部变量的作用域只在函数内其存储位置在栈区中当程序调用完函数后局部变量会随此函数一起被释放。其地址指向的内容不明原先的数值可能不变也可能改变。而局部静态变量地址和字符串常量地址存放在数据区动态分配地址存放在堆区函数运行结束后只会释放栈区的内容而不会改变数据区和堆区。 举例如下
#include iostreamint* display() {int num[3] {8,6,5};return num;
}int main() {int* p display();for(int i 0; i 3; i) {std::cout *(pi) std::endl;}return 0;
} 这段代码存在一个问题即在函数display()中返回了一个指向局部变量num的指针。这是不安全的操作因为当函数display()结束时局部变量num将被销毁指向它的指针p将变成悬空指针使用它可能导致未定义的行为。 上述程序输出结果为 若要完整的打印num数组中的3个数我们该怎么做呢
函数返回局部变量的地址通常有以下几种方法
1、返回一个字符串常量的指针 const char* buffer helloword;
#include iostreamconst char* display() {const char* buffer helloword;return buffer;
}int main() {const char* str;str display();std::cout str std::endl;return 0;
} 这样程序运行是没有问题的buffer存在只读内存区在 display() 退出的时候字符串常量不会被收回因此把地址赋给str时可以正确访问。 上面这个方式只是最简单的解决方案因为字符串存放在只读内存区以后需要修改它的时候就会很麻烦。
上述程序输出 以下为错误方法 char buffer[] helloword;
#includeiostream
char* display()
{char buffer[] helloword;return buffer;
}int main()
{char* str;str display();std::cout str;return 0;
}在display()函数中你定义了一个局部字符数组buffer并将其作为指针返回给主函数。然而当函数执行完毕后局部数组buffer的生命周期结束它所占用的内存将被释放。因此在主函数中访问指针str指向的值将会导致未定义的行为。 运行上述程序输出乱码。
2、使用全局声明的数组 没有使用全局声明的数组的情况
#include iostreamint* display() {int num[5] { 3,4,5,6,8 };return num;
}int main() {int* p;p display();for (int i 0; i 5; i) {std::cout *(p i ): *(p i) std::endl;}return 0;
}
输出结果 使用了全局声明的数组的情况
#include iostreamint num[5] { 3,4,5,6,8 };
int* display() {return num;
}int main() {int* p;p display();for (int i 0; i 5; i) {std::cout *(p i ): *(p i) std::endl;}return 0;
}
输出结果 这种情况简单容易。缺点就是任何人都有可能在任何时候修改这个全局数组而且该函数的下一次调用会覆盖数组的内容。
3、使用静态数组 static
#includeiostreamint* display() {static int num[5] { 3,4,5,6,8 };return num;
}int main() {int* p;p display();for (int i 0; i 5; i) {std::cout *(p i ): *(p i) std::endl;}return 0;
}
输出结果 使用静态数组可以保证内存不被回收而且可以防止任何人修改这个数组。只有拥有指向该数组的指针的函数才能修改这个静态数组不过同时该函数的下一次调用会覆盖数组的内容。同时和全局数组一样大型缓冲区闲置是非常浪费空间的。 补充
static int num[5]和int num[5]的区别在于变量的作用域和生命周期。
1. static int num[5]在函数内部或者代码块内部使用static关键字声明的数组称为静态数组。静态数组的特点是 - 作用域静态数组的作用域限定在声明它的函数内部或者代码块内部。 - 生命周期静态数组在程序运行期间一直存在即使函数执行完毕或者代码块结束数组仍然存在于内存中。 - 存储位置静态数组存储在静态存储区不会随着函数的调用而创建和销毁。
2. int num[5]只使用int关键字声明的数组称为自动数组也称为局部数组。自动数组的特点是 - 作用域自动数组的作用域限定在声明它的函数内部或者代码块内部。 - 生命周期自动数组的生命周期与所在的函数执行周期相关函数执行完毕或者代码块结束时数组会被销毁。 - 存储位置自动数组存储在栈上随着函数的调用和返回而动态创建和销毁。
总结 静态数组的作用于是全局的生命周期是整个程序运行期间存储在静态存储区 自动数组的作用域是局部的生命周期与所在函数相关存储在栈上。
4、显式的分配内存在堆上动态分配内存 new / malloc
使用new动态分配内存 #includeiostream
char* display()
{char* buffer new char[11];strcpy_s(buffer,11, helloworld);return buffer;
}int main()
{char* str;str display();std::cout str;delete[] str; // 释放内存return 0;
}
输出结果为 在上述代码中我们使用strcpy_s函数来进行字符串复制操作。注意我们还将缓冲区大小作为第二个参数传递给strcpy_s确保不会发生缓冲区溢出。 注意在使用动态内存分配时需要确保在不再使用时手动释放内存以避免内存泄漏。 使用malloc动态分配内存 #includeiostream
char* fun()
{int i;char* buffer (char*)malloc(sizeof(char) * 20); if (buffer ! NULL) {strcpy_s(buffer,20, abcdefgwwwwwwweeeww);}return buffer;
}int main()
{char* str;str fun();if (str ! NULL) {std::cout str std::endl;free(str); // 释放内存}return 0;
}输出结果 部分引用自
C/C 返回函数内局部变量和局部变量的地址_c返回地址的函数-CSDN博客