如何传递数组参数并避免数组"降价"

探讨C语言中数组降阶问题及C++通过数组引用解决该问题的方法。揭示为何在函数参数中传递数组会导致其退化为指针,并提供一种有效避免此现象的技术。
 

"数组引用"以避免"数组降阶"(本文曾贴于VCKBASE/C++论坛)

受[hpho]的一段模板函数的启发,特写此文,如有雷同,实在遗憾。
数组降阶是个讨厌的事,这在C语言中是个无法解决的问题,先看一段代码,了解什么是"数组降阶"

#include <IOSTREAM>
using namespace std;

void Test( char array[20] )
{
    cout << sizeof(array) << endl; // 输出 4
}

int main( void )
{
    char array[20] = { 0 };
    cout << sizeof(array) << endl; // 输出 20
    Test( array );
}

为什么同样申明的array一个输出20一个输出4?这是因为void Test( char array[20] )中的array被降阶处理了,void Test( char array[20] )等同于void Test( char array[] ),也等同于void Test( char* const array ),如果你BT(开玩笑),它也等同于void Test( char array[999] )。
就是说
void Test( char array[20] )
{
    cout << sizeof(array) << endl;
}
被降成
void Test( char* const array )
{
    cout << sizeof(array) << endl; // 既然是char*,当然输出4
}
这样一来问题大了,你完全可以定义一个不足20个元素的数组,然后传给Test,坐等程序崩溃。在一些要求较高的场合就不能使用数组做参数,真TMD心有不甘。

那么在C语言中怎样解决这个问题?
没办法,应该说没有好办法。a:做个结构,其中仅一个char array[20],然后用这个结构指针代替char array[20]。可见这是个很繁琐的办法,且不直观;b:在Test内部使用_msize来计算array长度。这更不行,首先它使得错误的发现被推迟到运行期,而不是编译期,其次_msize长度/元素大小>=array长度,也就是说就是new char[19]和new array[20]分配的大小是一样的,这样一来,虽不至于导致程序崩溃,但运算结果却不正确。

感谢[hpho],受其启发,C++中有C所没有的"引用",但数组引用是怎样申明的呢?经过几番试验,Look

#include <IOSTREAM>
using namespace std;

void Test( char (&array)[20] ) // 是不是很像 char *p[20] 和 char (*p)[20] 的区别?
{
    cout << sizeof(array) << endl;
}

int main( void )
{
    char array[20] = { 0 };
    cout << sizeof(array) << endl;
    Test( array );
}

好的以下是新的题目:# P2234 [HNOI2002] 营业额统计 ## 题目描述 Tiger 最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计分析公司成立以来的营业情况。 Tiger 拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:当最小波动值越大时,就说明营业情况越不稳定。 而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助 Tiger 来计算这一个值。 我们定义,一天的最小波动值 = $\min\{|\text{该天以前某一天的营业额}-\text{该天营业额}|\}$。 特别地,第一天的最小波动值为第一天的营业额。 ## 输入格式 第一行为正整数 $n$($n \leq 32767$) ,表示该公司从成立一直到现在的天数,接下来的 $n$ 行每行有一个整数 $a_i$($|a_i| \leq 10^6$) ,表示第 $i$ 天公司的营业额,可能存在负数。 ## 输出格式 输出一个整数,即每一天最小波动值的和,保证结果小于 $2^{31}$。 ## 输入输出样例 #1 ### 输入 #1 ``` 6 5 1 2 5 4 6 ``` ### 输出 #1 ``` 12 ``` ## 说明/提示 结果说明:$5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12$这是我的代码:// 营业额统计 #include <cstdio> #include <cstdlib> #define lc son[p][0] #define rc son[p][1] #define inf 0x3f3f3f3f const int N = 32767 + 37; int n, x, root = 0; int son[N][2], val[N], pri[N], num[N]; int min(int x, int y) { return x < y ? x : y; } void rotate(int &p, int dir) { int q = son[p][dir]; son[p][dir] = son[q][dir ^ 1]; son[q][dir ^ 1] = p; p = q; } void insert(int &p, int v) { static int idx = 0; if (!p) { p = ++ idx; val[p] = v; num[p] = 1; pri[p] = rand(); return; } if (v = val[p]) { num[p]++; } else if (v < val[p]) { insert(lc, v); if (pri[p] < pri[lc]) rotate(p, 0); } else { insert(rc, v); if (pri[p] < pri[rc]) rotate(p, 1); } } int getpre(int p, int v) { int pre = -inf; while (p) { if (val[p] <= v) { pre = val[p]; p = rc; } else p = lc; } return pre; } int getnext(int p, int v) { int next = inf; while (p) { if (val[p] >= v) { next = val[p]; p = lc; } else p = rc; } return next; } int main() { val[0] = -1e9; scanf("%d %d", &n, &x); int ans = x; insert(root, x); for (int i = 1; i < n; i++) { scanf("%d", &x); ans += min(x - getpre(root, x), getnext(root, x) - x); insert(root, x); } printf("%d\n", ans); return 0; } 可以忽略 /* 没有参数 显示帮助。这与键入 /? 是一样的。 /? 显示帮助。这与不键入任何选项是一样的。 /i 显示图形用户界面(GUI)。 这必须是第一个选项。 /l 注销。这不能与 /m 或 /d 选项一起使用。 /s 关闭计算机。 /r 关闭重新启动计算机。 /g 关闭重新启动计算机。系统重新启动后, 重新启动所有注册的应用程序。 /a 中止系统关闭。 这只能在超时期间使用。 /p 关闭本地计算机,没有超时或警告。 可以与 /d 和 /f 选项一起使用。 /h 休眠本地计算机。 可以与 /f 选项一起使用。 /e 记录计算机意外关闭的原因。 /m \\computer 指定目标计算机。 /t xxx 设置关闭前的超时为 xxx 秒。 有效范围是 0-315360000 (10 年),默认值为 30。 如果超时时间大于 0,则默示 /f 参数。 /c "comment" 重启动或关闭的原因的注释。 最多允许 512 个字符。 /f 强制正在运行的应用程序关闭,不前台警告用户。 当为 /t 参数指定大于 0 的值时, 则默示 /f 参数。 /d [p|u:]xx:yy 提供重新启动或关机的原因。 p 表明重新启动或关闭是计划内的。 u 表示原因由用户定义。 如果 p 和 u 均未指定,则是计划外重新启动 或关闭。 xx 是主要原因号(小于 256 的正整数)。 yy 是次要原因号(小于 65536 的正整数)。 */ 使代码AC
最新发布
08-20
### 问题1的整数规划模型框架与步骤 #### 1. 模型框架 我们建立混合整数线性规划(MILP)模型,核心框架如下: - **目标函数**:最大化总利润 = 销售收入 - 种植成本 - **决策变量**:二元种植决策 + 连续面积分配 - **核心约束**: - 耕地类型匹配 - 重茬约束(禁止连续种植相同作物) - 三年豆类轮作 - 最小种植面积 - 产量与销售平衡 #### 2. 建模步骤 ##### 步骤1:定义集合与参数 ```matlab % 基础集合 years = 2024:2030; % 规划年份 plots = land_data.地块名称; % 地块集合 crops = stats_data.作物名称; % 作物集合 seasons = ["第一季", "第二季", "单季"]; % 季节集合 legumes = ["黄豆","黑豆","红豆","绿豆","爬豆","豇豆","刀豆","芸豆"]; % 豆类作物 % 关键参数 min_area = 0.5; % 最小种植面积阈值(亩) yield = containers.Map(); % 亩产量字典 cost = containers.Map(); % 种植成本字典 price = containers.Map(); % 销售价格字典 demand = containers.Map();% 预期销售量 ``` ##### 步骤2:参数计算(预处理) ```matlab % 计算2023年各作物预期销售量(按季) for c = crops for s = seasons mask = (planting_data.作物名称 == c) & (planting_data.种植季次 == s); if any(mask) area_planted = planting_data.种植面积_亩(mask); plot_types = land_data.地块类型(ismember(land_data.地块名称, planting_data.种植地块(mask))); % 获取对应亩产量 total_yield = 0; for i = 1:sum(mask) plot_type = plot_types(i); y = stats_data.亩产量_斤(... stats_data.作物名称 == c & stats_data.地块类型 == plot_type); total_yield = total_yield + y * area_planted(i); end demand(strjoin([c,s], '_')) = total_yield; else demand(strjoin([c,s], '_')) = 0; end end end % 填充亩产量、成本、价格字典(使用中值) for i = 1:height(stats_data) crop = stats_data.作物名称{i}; plot_type = stats_data.地块类型{i}; key = strjoin([crop, plot_type], '_'); yield(key) = stats_data.亩产量_斤(i); cost(key) = stats_data.种植成本_元_亩_(i); % 处理价格区间 if ischar(stats_data.销售单价_元_斤_{i}) prices = sscanf(stats_data.销售单价_元_斤_{i}, '%f-%f'); price(key) = mean(prices); else price(key) = stats_data.销售单价_元_斤_{i}; end end ``` ##### 步骤3:定义决策变量 ```matlab % 二元决策变量:是否种植 z = optimvar('z', length(years), length(plots), length(seasons),... length(crops), 'Type', 'integer', 'LowerBound', 0, 'UpperBound', 1); % 连续决策变量:种植面积 a = optimvar('a', length(years), length(plots), length(seasons),... length(crops), 'LowerBound', 0); % 销售变量(情况1和2共用) y_sale = optimvar('y_sale', length(years), length(crops),... length(seasons), 'LowerBound', 0); ``` ##### 步骤4:建立目标函数 ```matlab % 情况1:滞销模型 revenue1 = optimexpr; for t = 1:length(years) for c = 1:length(crops) for s = 1:length(seasons) revenue1 = revenue1 + price(crops{c}) * y_sale(t, c, s); end end end % 情况2:降价模型 revenue2 = optimexpr; for t = 1:length(years) for c = 1:length(crops) for s = 1:length(seasons) % 总产量计算 total_yield = optimexpr; for i = 1:length(plots) plot_type = land_data.地块类型(land_data.地块名称 == plots{i}); key = strjoin([crops{c}, plot_type], '_'); total_yield = total_yield + yield(key) * a(t, i, s, c); end revenue2 = revenue2 + 0.5 * price(crops{c}) * (total_yield + y_sale(t, c, s)); end end end % 种植成本(共用) cultivation_cost = optimexpr; for t = 1:length(years) for i = 1:length(plots) for s = 1:length(seasons) for c = 1:length(crops) plot_type = land_data.地块类型(land_data.地块名称 == plots{i}); key = strjoin([crops{c}, plot_type], '_'); cultivation_cost = cultivation_cost + cost(key) * a(t, i, s, c); end end end end % 最终目标函数 model1 = optimproblem('ObjectiveSense', 'maximize'); model1.Objective = revenue1 - cultivation_cost; model2 = optimproblem('ObjectiveSense', 'maximize'); model2.Objective = revenue2 - cultivation_cost; ``` ##### 步骤5:添加约束条件 ```matlab % 约束1:地块面积约束 area_constr = optimconstr(length(years), length(plots), length(seasons)); for t = 1:length(years) for i = 1:length(plots) for s = 1:length(seasons) total_area = sum(a(t, i, s, :)); area_constr(t, i, s) = total_area <= land_data.地块面积_亩(i); end end end model1.Constraints.area_constr = area_constr; model2.Constraints.area_constr = area_constr; % 约束2:最小种植面积 min_area_constr = optimconstr(length(years), length(plots), length(seasons), length(crops)); for t = 1:length(years) for i = 1:length(plots) for s = 1:length(seasons) for c = 1:length(crops) min_area_constr(t, i, s, c) = a(t, i, s, c) >= min_area * z(t, i, s, c); min_area_constr(t, i, s, c) = a(t, i, s, c) <= land_data.地块面积_亩(i) * z(t, i, s, c); end end end end model1.Constraints.min_area_constr = min_area_constr; model2.Constraints.min_area_constr = min_area_constr; % 约束3:重茬约束 replant_constr = optimconstr(length(years)-1, length(plots), length(seasons), length(crops)); for t = 1:length(years)-1 for i = 1:length(plots) for s = 1:length(seasons) for c = 1:length(crops) replant_constr(t, i, s, c) =... z(t, i, s, c) + z(t+1, i, s, c) <= 1; end end end end model1.Constraints.replant_constr = replant_constr; model2.Constraints.replant_constr = replant_constr; % 约束4:豆类轮作 legume_constr = optimconstr(length(years)-2, length(plots)); for t = 1:length(years)-2 for i = 1:length(plots) legume_sum = optimexpr; for k = t:t+2 for s = 1:length(seasons) for c = 1:length(crops) if ismember(crops{c}, legumes) legume_sum = legume_sum + z(k, i, s, c); end end end end legume_constr(t, i) = legume_sum >= 1; end end model1.Constraints.legume_constr = legume_constr; model2.Constraints.legume_constr = legume_constr; % 约束5:耕地类型匹配 land_type_constr = optimconstr(length(years), length(plots), length(seasons), length(crops)); for t = 1:length(years) for i = 1:length(plots) plot_type = land_data.地块类型(land_data.地块名称 == plots{i}); for s = 1:length(seasons) for c = 1:length(crops) crop_type = stats_data.作物类型(stats_data.作物名称 == crops{c}); % 根据地块类型和作物类型设置约束 if plot_type == "平旱地" || plot_type == "梯田" || plot_type == "山坡地" % 仅允许粮食作物,单季 if ~contains(crop_type, '粮食') || s ~= find(seasons == "单季") land_type_constr(t, i, s, c) = z(t, i, s, c) == 0; end elseif plot_type == "水浇地" % 特殊处理:水稻或蔬菜轮作 if crops{c} == "水稻" % 水稻只能单季,且第二季不能种植 if s == find(seasons == "单季") % 允许种植 else land_type_constr(t, i, s, c) = z(t, i, s, c) == 0; end else % 蔬菜作物:第一季任意蔬菜,第二季特定蔬菜 if s == find(seasons == "第二季") &&... ~ismember(crops{c}, ["大白菜","白萝卜","红萝卜"]) land_type_constr(t, i, s, c) = z(t, i, s, c) == 0; end end elseif plot_type == "普通大棚" % 第一季蔬菜,第二季食用菌 if s == find(seasons == "第一季") &&... ~contains(crop_type, '蔬菜') land_type_constr(t, i, s, c) = z(t, i, s, c) == 0; elseif s == find(seasons == "第二季") &&... ~contains(crop_type, '食用菌') land_type_constr(t, i, s, c) = z(t, i, s, c) == 0; end elseif plot_type == "智慧大棚" % 两季均蔬菜,禁种特定作物 if ~contains(crop_type, '蔬菜') ||... ismember(crops{c}, ["大白菜","白萝卜","红萝卜"]) land_type_constr(t, i, s, c) = z(t, i, s, c) == 0; end end end end end end model1.Constraints.land_type_constr = land_type_constr; model2.Constraints.land_type_constr = land_type_constr; % 约束6:销售平衡 sale_constr1 = optimconstr(length(years), length(crops), length(seasons)); sale_constr2 = optimconstr(length(years), length(crops), length(seasons)); for t = 1:length(years) for c = 1:length(crops) for s = 1:length(seasons) key = strjoin([crops{c}, seasons{s}], '_'); % 产量计算 total_yield = optimexpr; for i = 1:length(plots) plot_type = land_data.地块类型(land_data.地块名称 == plots{i}); y_key = strjoin([crops{c}, plot_type], '_'); total_yield = total_yield + yield(y_key) * a(t, i, s, c); end % 销售量不能超过产量和预期需求 sale_constr1(t, c, s) = y_sale(t, c, s) <= total_yield; sale_constr2(t, c, s) = y_sale(t, c, s) <= demand(key); end end end model1.Constraints.sale_constr1 = sale_constr1; model1.Constraints.sale_constr2 = sale_constr2; model2.Constraints.sale_constr1 = sale_constr1; model2.Constraints.sale_constr2 = sale_constr2; ``` ##### 步骤6:模型求解与结果输出 ```matlab % 求解情况1(滞销) opts = optimoptions('intlinprog',... 'Display', 'iter',... 'MaxTime', 3600,... 'Heuristics', 'advanced',... 'CutGeneration', 'advanced'); [sol1, fval1] = solve(model1, 'Options', opts); % 求解情况2(降价) [sol2, fval2] = solve(model2, 'Options', opts); % 结果提取与保存 results_table = table(); for t = 1:length(years) for i = 1:length(plots) for s = 1:length(seasons) for c = 1:length(crops) if sol1.a(t, i, s, c) > 0.01 % 忽略极小面积 new_row = {years(t), plots{i}, seasons{s},... crops{c}, sol1.a(t, i, s, c)}; results_table = [results_table; new_row]; end end end end end results_table.Properties.VariableNames =... {'年份', '地块', '季节', '作物', '种植面积'}; % 保存到Excel writetable(results_table, 'result_1.xlsx'); 将这段代码优化一下,基于MATLAB(2024A)
06-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值