Параметр bn1 изменяется как внутри
BigNum_add так и в BigNum_sub.
Cледовало бы ожидать что измененное значение передастся в вызывающую
процедуру BigNum_add и еще выше в вызывающую BigNum_addфункцию
Но этого не происходит.
И не должно происходить.
Параметры в языке C передаются в функции только
по значению (как локальные копии оригинального аргумента). Изменяя параметры, вы меняете лишь значение этой копии; сам оригинал остается неизменным. После выхода из функции копия прекращает существование, и от изменения не остается и следа.
А вот тут позвольте не согласиться
void display_values(int *a, int *b) {
*a=1000; *b=1
}
void main() {
int a= 2002, b = 0;
display_values(&a, &b);
pruntf(“%i %i”,a,b); //стало a=1000; b=1;
Это есть и было в С
Добавлено через 11 минут и 40 секунд:Это прога попытка реализации арифметики длинных чисел. Каждое число -структура Bignum есть знак sign, массив data - четверок 10-ичных чисел
вот даже вставил отладочную печать функция BigNum_add в случае когда знаки слагаемых разные вызывает
BigNum_sub и в той и в другой изменяется переданное по ссылке bn1. Тест 1+ (-10) должен быть=-9
Перед выходом из BigNum_sub bn1=-9 точнее bn1->sign=-1, bn1->data[0]=9 а сразу же после возврата в BigNum_add - bn1->sign=1, bn1->data[0]=1 т.е=1
Вроде передача структуры по ссылке не противоречит правилам С. Тогда это может быть вызвано другими причинами смещением памяти или что-то вроде?
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define MAXVAL 10000
typedef struct BigNum {
int sign; // Знак числа, 1 или -1.
int *data; // Массив с частями числа.
// Каждая часть хранит числа от 0 до 9999 включительно,
// что соответствует записи числа в системе с основанием
// 10000.
// data[0] хранит в себе младший разряд числа.
size_t size; // Размер массива data.
} BigNum;
// Фукнции максимума и минимума для удобства.
int MIN(int a, int b)
{ return (a < b) ? a : b;}
int MAX(int a, int b)
{ return (a < b) ? b : a;}
BigNum *BigNum_make(char *source)
{ int i, k = 0;int power;
BigNum *bn = (BigNum *) malloc(sizeof(BigNum));
if (source[0] == '-') {
bn->sign = -1;source++; // пропустить знак '-'
}
else {bn->sign = 1;}
// Чтобы при целочисленном делении a / n сделать оругление
// в большую сторону, используем (a + (n-1)) / n.
bn->size = (strlen(source) + 3) / 4;
bn->data = (int *) malloc(sizeof(int) * bn->size);
// Считываем из массива все разряды по осн 10000,
// начиная с младшего. Старший разряд обработаем позже.
for (i = strlen(source) - 1; i >= 4; i -= 4) {
bn->data[k] = 1000*(source[i - 3]-'0') +
100*(source[i-2] - '0')+10*(source[i-1]-'0')+(source[i]-'0');
k++;
}
//Так как в старшем разряде может быть менее 4 десятичных цифр,обработаем его отдельно.
bn->data[k] = 0;
power = 1;
for (; i >= 0; i--) {
bn->data[k] = bn->data[k] + (source[i] - '0') * power;
power *= 10;
}
return bn;
}
BigNum *BigNum_copy(BigNum * bn)
{
// Надо выделить память под новую структуру BigNum и
// под её внутренний массив, и скопировать в них соотв содерж из bn.
int i;
BigNum *bn1 = (BigNum *) malloc(sizeof(BigNum));
bn1->size=bn->size;bn1->sign=bn->sign;
bn1->data=(int *)malloc(bn1->size*sizeof(int));
for(i=0;i<bn1->size;i++)
bn1->data[i]=bn->data[i];
}
void BigNum_free(BigNum * bn)
{
free(bn->data);
free(bn);
}
void BigNum_print(BigNum * bn)
{ int i;
if (bn->sign < 0) printf("-\n");
// Печатаем разряды, начиная со старшего.
for (i = bn->size - 1; i >= 0; i--)
{printf("%04d", bn->data[i]);}
printf("\n");
}
void BigNum_set_size(BigNum * bn, size_t new_size)
{ // Функция для установки нового размера внутреннего массива.
// если размер массива увеличился, нужно занулить новые элементы.
int i;
if (new_size> bn->size) {
for(i=bn->size;i<new_size;i++)
bn->data[i]=0;
};
bn->size=new_size;
}
void BigNum_add(BigNum * bn1, BigNum * bn2) // +=
{// 1 2312 3123 + 9 8798 7987 // 1 + 9999 9999 //9999 9999 9999 + 1
// Функия неправ работает при сложении положит и отриц числа.
// Дораб её, чтобы она раб корректно и добавьте соотв тесты в run_tests() в main.c
int i, x = 0;
if (bn1->sign==bn2->sign) {//знаки совпадают
BigNum_set_size(bn1,MAX(bn1->size,bn2->size)+1);
for (i = 0; i < bn2->size; i++) {
bn1->data[i] += bn2->data[i] + x;
x = bn1->data[i] / MAXVAL; // Получаем 1 (при переполнении) или 0 для переноса в следующий разряд.
bn1->data[i] %= MAXVAL; // Убираем всё лишнее.
}
for (; i < bn1->size && x != 0; i++) // продолжаем распространять единицу, если она есть.
{ bn1->data[i] += x; x = bn1->data[i] / MAXVAL; bn1->data[i] %= MAXVAL;}
if (bn1->data[bn1->size-1]==0) bn1->size--;
}//знаки совпадают
else {//знаки не совпадают
bn2->sign=-bn2->sign;BigNum_sub(bn1,bn2);
[b] printf("otl2 bn1->data[0]= %i\n",bn1->data[0]);[/b]
bn2->sign=-bn2->sign;
};
}
void BigNum_sub(BigNum * bn1, BigNum * bn2)
{//Операция -=
int i, x = 0;BigNum *w1;
if (bn1->sign==bn2->sign) {//знаки совпадают
if(BigNum_gt(bn1,bn2)==1){//bn1>=bn2
BigNum_set_size(bn1,bn1->size);
for (i =0; i<bn2->size;i++) {
bn1->data[i]-= bn2->data[i];
if ( bn1->data[i]<0)
{bn1->data[i]+=MAXVAL; bn1->data[i+1]--;};
}
}//bn1>=bn2
else {//bn2>bn1
w1=BigNum_copy(bn1);BigNum_set_size(bn1,bn2->size);
bn1=BigNum_copy(bn2);bn1->sign=-1;
for (i =0; i<w1->size;i++) {
bn1->data[i]-= w1->data[i];
if ( bn1->data[i]<0)
{bn1->data[i]+=MAXVAL; bn1->data[i+1]--;};
}
};
}//знаки совпадают
else {//знаки не совпадают
bn2->sign=-bn2->sign;BigNum_add(bn1,bn2);
};
[b] printf("otl1 bn1->data[0]= %i\n",bn1->data[0]);[/b]
}
int BigNum_gt(BigNum * bn1, BigNum * bn2)//>
{
if (bn1->size<bn2->size) return 0;
if (bn1->size>bn2->size) return 1;
if (bn1->data[bn1->size-1]>=bn2->data[bn2->size-1])return 1;
else return 0;
}
int BigNum_eq(BigNum * bn1, BigNum * bn2) // ==
{// Функция проверки на равенство.
//числа разной длины тоже м б равны если в числе большего разм в "лишних" разрядах стоят 0
int i,mn;
if (bn1->sign != bn2->sign)
{return 0;}
if(bn1->size<bn2->size) {
mn=bn1->size;
for(i=bn1->size;i<bn2->size;i++)
if (bn2->data[i] != 0) return 0;
};
if(bn2->size<bn1->size) {
mn=bn2->size;
for(i=bn2->size;i<bn1->size;i++)
if (bn1->data[i] != 0) return 0;
}
else mn=bn1->size;
for (i=0;i<mn;i++)
if (bn1->data[i] !=bn2->data[i]) return 0;
return 1;
}
void BigNum_check_add(char *bn1_str, char *bn2_str, char *result_str)
{ // Создаём большие числа из строк.
BigNum *bn1 = BigNum_make(bn1_str), *bn2 = BigNum_make(bn2_str),
*result = BigNum_make(result_str);
// Делаем копию bn1, чтобы иметь неизменённое число,
// если нужно будет вывести сообщение об ошибке.
BigNum *bn1_copy = (BigNum *) BigNum_copy(bn1);
BigNum_add(bn1_copy, bn2); // Складываем числа, результат в bn1_copy.
if (!BigNum_eq(bn1_copy, result)) { // Если результат перемножения не равен заданному,
// напечатаем ошибку и выйдем из функции.
printf("Can not add\n ");BigNum_print(bn1);printf(" to\n ");BigNum_print(bn2);
printf(" Expected\n ");BigNum_print(result);printf(" got\n ");BigNum_print(bn1_copy);
return;
}
// Освободим память, чтобы не было утечек.
BigNum_free(bn1), BigNum_free(bn2), BigNum_free(result);
//BigNum_free(bn1_copy);
}
void BigNum_mul(BigNum * bn1, BigNum * bn2)
{// Операция *=
}
#include "bignum.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define MAXVAL 10000
// Фукнции максимума и минимума для удобства.
int MIN(int a, int b)
{ return (a < b) ? a : b;}
int MAX(int a, int b)
{ return (a < b) ? b : a;}
BigNum *BigNum_make(char *source)
{ int i, k = 0;int power;
BigNum *bn = (BigNum *) malloc(sizeof(BigNum));
if (source[0] == '-') {
bn->sign = -1;source++; // пропустить знак '-'
}
else {bn->sign = 1;}
// Чтобы при целочисленном делении a / n сделать оругление
// в большую сторону, используем (a + (n-1)) / n.
bn->size = (strlen(source) + 3) / 4;
bn->data = (int *) malloc(sizeof(int) * bn->size);
// Считываем из массива все разряды по осн 10000,
// начиная с младшего. Старший разряд обработаем позже.
for (i = strlen(source) - 1; i >= 4; i -= 4) {
bn->data[k] = 1000*(source[i - 3]-'0') +
100*(source[i-2] - '0')+10*(source[i-1]-'0')+(source[i]-'0');
k++;
}
//Так как в старшем разряде может быть менее 4 десятичных цифр,обработаем его отдельно.
bn->data[k] = 0;
power = 1;
for (; i >= 0; i--) {
bn->data[k] = bn->data[k] + (source[i] - '0') * power;
power *= 10;
}
return bn;
}
BigNum *BigNum_copy(BigNum * bn)
{
// Надо выделить память под новую структуру BigNum и
// под её внутренний массив, и скопировать в них соотв содерж из bn.
int i;
BigNum *bn1 = (BigNum *) malloc(sizeof(BigNum));
bn1->size=bn->size;bn1->sign=bn->sign;
bn1->data=(int *)malloc(bn1->size*sizeof(int));
for(i=0;i<bn1->size;i++)
bn1->data[i]=bn->data[i];
}
void BigNum_free(BigNum * bn)
{
free(bn->data);
free(bn);
}
void BigNum_print(BigNum * bn)
{ int i;
if (bn->sign < 0) printf("-\n");
// Печатаем разряды, начиная со старшего.
for (i = bn->size - 1; i >= 0; i--)
{printf("%04d", bn->data[i]);}
printf("\n");
}
void BigNum_set_size(BigNum * bn, size_t new_size)
{ // Функция для установки нового размера внутреннего массива.
// если размер массива увеличился, нужно занулить новые элементы.
int i;
if (new_size> bn->size) {
for(i=bn->size;i<new_size;i++)
bn->data[i]=0;
};
bn->size=new_size;
}
void BigNum_add(BigNum * bn1, BigNum * bn2) // +=
{// 1 2312 3123 + 9 8798 7987 // 1 + 9999 9999 //9999 9999 9999 + 1
// Функия неправ работает при сложении положит и отриц числа.
// Дораб её, чтобы она раб корректно и добавьте соотв тесты в run_tests() в main.c
int i, x = 0;
if (bn1->sign==bn2->sign) {//знаки совпадают
BigNum_set_size(bn1,MAX(bn1->size,bn2->size)+1);
for (i = 0; i < bn2->size; i++) {
bn1->data[i] += bn2->data[i] + x;
x = bn1->data[i] / MAXVAL; // Получаем 1 (при переполнении) или 0 для переноса в следующий разряд.
bn1->data[i] %= MAXVAL; // Убираем всё лишнее.
}
for (; i < bn1->size && x != 0; i++) // продолжаем распространять единицу, если она есть.
{ bn1->data[i] += x; x = bn1->data[i] / MAXVAL; bn1->data[i] %= MAXVAL;}
if (bn1->data[bn1->size-1]==0) bn1->size--;
}//знаки совпадают
else {//знаки не совпадают
bn2->sign=-bn2->sign;BigNum_sub(bn1,bn2);
printf("otl2 bn1->data[0]= %i\n",bn1->data[0]);
bn2->sign=-bn2->sign;
};
}
void BigNum_sub(BigNum * bn1, BigNum * bn2)
{//Операция -=
int i, x = 0;BigNum *w1;
if (bn1->sign==bn2->sign) {//знаки совпадают
if(BigNum_gt(bn1,bn2)==1){//bn1>=bn2
BigNum_set_size(bn1,bn1->size);
for (i =0; i<bn2->size;i++) {
bn1->data[i]-= bn2->data[i];
if ( bn1->data[i]<0)
{bn1->data[i]+=MAXVAL; bn1->data[i+1]--;};
}
}//bn1>=bn2
else {//bn2>bn1
w1=BigNum_copy(bn1);BigNum_set_size(bn1,bn2->size);
bn1=BigNum_copy(bn2);bn1->sign=-1;
for (i =0; i<w1->size;i++) {
bn1->data[i]-= w1->data[i];
if ( bn1->data[i]<0)
{bn1->data[i]+=MAXVAL; bn1->data[i+1]--;};
}
};
}//знаки совпадают
else {//знаки не совпадают
bn2->sign=-bn2->sign;BigNum_add(bn1,bn2);
};
printf("otl1 bn1->data[0]= %i\n",bn1->data[0]);
}
int BigNum_gt(BigNum * bn1, BigNum * bn2)//>
{
if (bn1->size<bn2->size) return 0;
if (bn1->size>bn2->size) return 1;
if (bn1->data[bn1->size-1]>=bn2->data[bn2->size-1])return 1;
else return 0;
}
int BigNum_eq(BigNum * bn1, BigNum * bn2) // ==
{// Функция проверки на равенство.
//числа разной длины тоже м б равны если в числе большего разм в "лишних" разрядах стоят 0
int i,mn;
if (bn1->sign != bn2->sign)
{return 0;}
if(bn1->size<bn2->size) {
mn=bn1->size;
for(i=bn1->size;i<bn2->size;i++)
if (bn2->data[i] != 0) return 0;
};
if(bn2->size<bn1->size) {
mn=bn2->size;
for(i=bn2->size;i<bn1->size;i++)
if (bn1->data[i] != 0) return 0;
}
else mn=bn1->size;
for (i=0;i<mn;i++)
if (bn1->data[i] !=bn2->data[i]) return 0;
return 1;
}
void BigNum_check_add(char *bn1_str, char *bn2_str, char *result_str)
{ // Создаём большие числа из строк.
BigNum *bn1 = BigNum_make(bn1_str), *bn2 = BigNum_make(bn2_str),
*result = BigNum_make(result_str);
// Делаем копию bn1, чтобы иметь неизменённое число,
// если нужно будет вывести сообщение об ошибке.
BigNum *bn1_copy = (BigNum *) BigNum_copy(bn1);
BigNum_add(bn1_copy, bn2); // Складываем числа, результат в bn1_copy.
if (!BigNum_eq(bn1_copy, result)) { // Если результат перемножения не равен заданному,
// напечатаем ошибку и выйдем из функции.
printf("Can not add\n ");BigNum_print(bn1);printf(" to\n ");BigNum_print(bn2);
printf(" Expected\n ");BigNum_print(result);printf(" got\n ");BigNum_print(bn1_copy);
return;
}
// Освободим память, чтобы не было утечек.
BigNum_free(bn1), BigNum_free(bn2), BigNum_free(result);
//BigNum_free(bn1_copy);
}
void main()
{
BigNum_check_add("1", "-10", "-9");
}