【问题标题】:C Program - Storing value in a pointer varaibleC程序 - 将值存储在指针变量中
【发布时间】:2016-06-02 20:17:05
【问题描述】:

我正在编写一个代码,要求用户输入 2 个矩阵的行数和列数,然后再要求用户输入其元素。

在获取矩阵元素的用户输入之后。函数matadd被调用,它接收数组变量a[20][20]的地址,b[20][20]包含第一个和第二个矩阵的元素,变量m的地址,n包含没有。行和列,数组变量s[20][20] 的地址,它将存储两个矩阵的和。

matadd功能码:

int matadd(int *(h)[20], int *(k)[20], int *u, int *l,int *(m)[20])
{
//VARIABLE-DECLARATION
int i = 0, j = 0;

for (i = 0; i < *u; i++)
{
    for (j = 0; j < *l; j++)
    {
        *(*(m + i) + j) = *(*(h + i) + j) + *(*(k + i) + j);
    }
}

printf("The Addition of above two given matrices is given below :\n");

printf("--           --\n");
for (i = 0; i < *u; i++)
{
     for (j = 0; j < *l; j++)
    {
        printf("|");
        for (j = 0; j < *l; j++)
        {
            printf("%4d", *(*(m + i) + j));
        }
        printf(" | ");
        printf("\n");
    }
}
printf("--           --\n");

return(m);

}

问题出在*(*(m + i) + j) = *(*(h + i) + j) + *(*(k + i) + j);这行代码,它必须在指针变量m内一一分配附加值。

但是程序停在那里并给我错误:

在 mATRIX_pROTO.exe 中的 0x00C124B9 处引发异常:0xC0000005:访问 违规读取位置0x00000001。

如果有这个异常的处理程序,程序可能是安全的 继续。

找不到代码有什么问题。我正在使用 Visual Studio 2015 来调试我的代码。

任何帮助将不胜感激。

这是我的代码:

//CONSTANT-VARIABLE
#define MAX 1000

//USER-DEFINED FUCNTION
int matadd(int *h, int *k, int *u, int *l,int *(m)[20]);
char xgets(char *line, int size, FILE *stdi);
void header(void);

char xgets(char *line, int size, FILE *stdi) {
  /* read a line from the user */
 fgets(line, size, stdi);

  /* strip the \n if present */
  line[strcspn(line, "\n")] = '\0';
 return line;
}

void header(void)
{
printf("*-*-*-*-*MATRIX_ADD_PTR*-*-*-*-*");
printf("\n\n");
}

//PROGRAM STARTS HERE
int main(void)
{
 //FUCNTION CALL-OUT
header();

//VARIABLE-DECLARATION
int a[20][20] = { { 0 } }, b[20][20] = { { 0 } }, c[20][20] = { { 0 } },s[20][20] = { {0} };
int i = 0, j = 0;
int m = 0, n = 0, q = 0, w = 0;
int line[MAX] = { 0 };

printf("Type Same Number of ROWs And COLUMNs for Both Matrx \n\n");

printf("Enter the No. of ROWs needed in First Matrix : ");
xgets(line, sizeof(line), stdin);
sscanf_s(line, "%d", &m);
printf("\n");

printf("Enter the No. of COLUMNs needed in First Matrix : ");
xgets(line, sizeof(line), stdin);
sscanf_s(line, "%d", &n);
printf("\n");

printf("Enter the Elements for 1st ROW then 2nd and So on for First Matrix : \n");
for (i = 0; i < m; i++)
{
    for (j = 0; j < n; j++)
    {
        xgets(line, sizeof(line), stdin);
        sscanf_s(line, "%d", &a[i][j]);
    }
}

printf("\n");

printf("Enter the No. of ROWs needed in Second Matrix : ");
xgets(line, sizeof(line), stdin);
sscanf_s(line, "%d", &q);
printf("\n");

printf("Enter the No. of COLUMNs needed in Second Matrix : ");
xgets(line, sizeof(line), stdin);
sscanf_s(line, "%d", &w);
printf("\n");

printf("Enter the Elements for 1st ROW then 2nd and So on for Second Matrix : \n");
for (i = 0; i < q; i++)
{
    for (j = 0; j < w; j++)
    {
        xgets(line, sizeof(line), stdin);
        sscanf_s(line, "%d", &b[i][j]);
    }
}

//OUTPUT OF ENTERED MATRIX
printf("First Matrix : \n\n");

printf("--        --\n");
for (i = 0; i < m; i++)
{
    printf("|");
    for (j = 0; j < n; j++)
    {
        printf("%3d", a[i][j]);
    }
    printf(" | ");
    printf("\n");
}
printf("--        --\n\n\n");

printf("Second Matrix : \n\n");

printf("--        --\n");
for (i = 0;i < q;i++)
{
    printf("|");
    for (j = 0; j < q; j++)
    {
        printf("%3d", b[i][j]);
    }
    printf(" | ");
    printf("\n");
}
printf("--        --\n\n\n");

//FUCNTION CALL-OUT
matadd(a, b, &m, &n, s);

//TERMINAL-PAUSE
system("pause");
}


int matadd(int *(h)[20], int *(k)[20], int *u, int *l,int *(m)[20])
{
    //VARIABLE-DECLARATION
    int i = 0, j = 0;

    for (i = 0; i < *u; i++)
{
        for (j = 0; j < *l; j++)
     {
        *(*(m + i) + j) = *(*(h + i) + j) + *(*(k + i) + j);
     }
 }

printf("The Addition of above two given matrices is given below :\n");

printf("--           --\n");
for (i = 0; i < *u; i++)
{
    for (j = 0; j < *l; j++)
     {
        printf("|");
        for (j = 0; j < *l; j++)
         {
            printf("%4d", *(*(m + i) + j));
         }
        printf(" | ");
        printf("\n");
    }
}
printf("--           --\n");

return(m);

}

【问题讨论】:

  • int *(h)[20] 等是 no 二维数组(又名矩阵)。它衰减为指向指针的指针,该指针不能是二维数组。也许你的意思是int (*h)[20] 可以用于二维数组。也不要使用幻数。一旦你的代码增长,它们最终会导致错误。
  • 1:名称。您的。变量。和。参数。 2:你的函数原型和它的定义不匹配。
  • 代码甚至无法编译,xgets 应该返回 char,但尝试返回 char *(行)。
  • @olaf 是的,我声明了它们,所以我可以将它们用于 2D 数组,我不会使用任何幻数来处理那个;)谢谢回复。
  • 启用 all 警告,并将每一个警告都视为错误。你用的是哪个编译器?

标签: c arrays pointers matrix


【解决方案1】:

您不能忽略 Visual Studio 编译器发出的所有警告。添加提到的包括stdlib.hstdio.hprocess.h 并将开关/TC 添加到编译器调用后,以下警告

警告 C4047: 'function' : 'int *' 与 'int [20][20]' 的间接级别不同

警告 C4024: 'matadd' : 形参和实参 1 的不同类型

排队

matadd(a, b, &m, &n, s);

清楚地表明你的代码出了问题。发出这些警告是因为您的函数原型需要 int *,而您在调用中给出了 int [20][20]。然而,函数原型与您对matadd 的定义不匹配。如果我将原型更改为

int matadd(int *(h)[20], int *(k)[20], int *u, int *l,int *(m)[20]);

编译器会发出以下警告:

警告 C4047: 'function' : 'int **' 与 'int [20][20]' 的间接级别不同

警告 C4024: 'matadd' : 形参和实参 1 的不同类型

您可以通过将原型和定义更改为:

int matadd(int (*h)[20], int (*k)[20], int *u, int *l,int (*m)[20]);

编辑: int (*h)[20] 类型实际上表示一个指向具有 20 个元素的数组的指针。如果将指针加 1 并使用 (*(h+1)) 取消引用它,那么您将在 (*h) 指向的前 20 个元素之后获得接下来的 20 个元素,依此类推。您还可以使用声明 int h[][20] 来表达它,它更好地显示了作为 2D 数组的预期用途。请注意,只有第一个维度的大小可以不定义。 (herehere 讨论的可能性更多,但 Visual Studio 2010 不支持这些。)

编辑:您可以实现matadd 函数,而无需任何显式指针算法。这是一个精简的例子:

#include <stdio.h>

// specifying the size of the first dimension is optional
void matadd(int h[][20], int k[][20], int u, int l, int m[][20])
{
    int i = 0, j = 0;

    for (i = 0; i < u; i++)
    {
        for (j = 0; j < l; j++)
        {
            m[i][j] = h[i][j] + k[i][j];
        }
    }
}

int main(void)
{
    int i, j, m, n;
    int a[20][20] = { { 0 } }, b[20][20] = { { 0 } }, s[20][20] = { {0} };

    m = 2; n = 2;
    a[0][0] = 1; a[0][1] = 2; a[1][0] = 3; a[1][1] = 4;
    b[0][0] = 5; b[0][1] = 6; b[1][0] = 7; b[1][1] = 8;

    matadd(a, b, m, n, s);

    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            printf("%4d | ", s[i][j]);
        }
        printf("\n");
    }
}

如编译器警告所示,您的代码甚至需要更多修复;

警告 C4013:“strcspn”未定义;假设 extern 返回 int

因为您忘记包含string.h

警告 C4047: 'function' : 'char' 与 'char *' 的间接级别不同

return line;return(m);。在这里,您将指针转换为字符。程序在这里没有段错误,因为你很高兴没有使用返回值。

警告 C4133: 'function' : 不兼容的类型 - 从 'int [1000]' 到 'char *' 警告 C4133: 'function' : 不兼容的类型 - 从 'int [1000]' 到 'const char *'

xgetssscanf_s 的电话下。这种类型转换也是无效的。该程序没有段错误,因为int [1000] 比相应的char [1000] 大。


我之前在 cmets 中引发讨论的长评论可以找到here

【讨论】:

  • 代码运行完美马丁我不知道你的 Visual Studio 有什么问题。请再次检查。
  • @Eddy 当然,xgets 的无效返回类型现在只是警告。但是 matadd 的声明和定义中的不兼容类型以及该函数调用中的过多参数仍然是 错误,甚至应该由 Visual Studio 报告。
  • @Eddy 这清楚地表明您发布了错误的代码。您的代码需要 string.h 才能获得 strcspn。我已经将它与stdlib.hstdio.h 一起添加并得到了上述结果。 process.h 是 Microsoft 特定的,但这里似乎不需要。
  • @DanielJour 是的,我知道数组衰减为指针。我还提到了int (*h)[20] 作为第一个修复。我的较长示例的目的是表明可以在没有任何 explicit 指针算法的情况下实现matadd。我在回答中澄清了这一点。
  • @Eddy 是的,我明白了。而且您必须至少将函数签名更改为int matadd(int (*h)[20], int (*k)[20], int *u, int *l,int (*m)[20]);。通过此更改,您的代码可以正常工作。您可以将指针算法保留在函数内部。
【解决方案2】:

查看您的添加代码,我们看到此模式三遍:

*(*(h + i) + j)

上面的表达式应该是int 类型,以便在元素添加的上下文中有意义。这意味着

(*(h + i) + j)

应该是int *类型,即指向整数的指针。这也意味着j 应该可以有意义地转换为size_t(它是)并且

*(h + i)

应该int *类型。那么

(h + i)

应该是指向上述类型的指针,因此是int **。类似于上面的i 应该可以转换为size_t(它是)并且h 应该具有相同的类型。

更直接地说,它应该是一个指向int(s)的(一个数组)的指针。

让我们看看你在main有什么:

int a[20][20];

这是一个数组数组,因此除了索引类似于

int a[20*20];

因为它存储在连续的内存中。这是与上面不同的表示形式!

您需要选择其中一种表示形式。

我尝试使用较小的 2 对 2 情况来可视化这一点(我在移动设备上,因此这样就够难了):

data:
1 2
3 4

你的函数期望你的数据是这样的:

@some_address:
  address_one <--- h points to this
  address_two

@address_one:
  1
  2

@address_two:
  3
  4

但你是这样存储的:

@some_address:
  1 <--- a decays to a pointer pointing to here upon use
  2
  3
  4

因此,您的函数使用值 12 作为内存地址。

请注意,我只是在这里解决(恕我直言)主要问题,还有很多问题需要解决,正如另一个答案中的示例编译器消息所示。

【讨论】:

  • 感谢丹尼尔的回复。但是我没明白你到底想说什么,你能详细说明一下吗?
  • 对不起 - 我理解了你试图解释的 50% - 如果你不介意你可以编辑我的 C 代码并发布它吗?
  • 我还想说,当我在 Visual Studio 2015 中运行我的代码时,它不会向我显示任何类型的警告和错误。
猜你喜欢
  • 1970-01-01
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-19
  • 1970-01-01
  • 1970-01-01
  • 2021-06-03
相关资源
最近更新 更多