0

I'm a complete C beginner, just started a week or two ago and I'm mainly using the book "C: a Modern Approach," and I'm really, really struggling with pointers, I'm trying to code a function that prompts the user to input a matrix row by row i.e. user enters row 1, presses enter, etc.

this is the code I have so far:

    for(int (*p)[M] = &a[0][0]; p <= &a[N-1][M-1]; p++)
    {
        scanf("%d", p);
    }

I've been struggling with this for pretty much the past 5 hours and I've looked on numerous websites but couldn't find anything to help. Would the new line thing factor into this? scanf just confuses me. Could this code somehow be modified to avoid having the user enter the dimensions of the matrix? Could it somehow detect the new line character?

I know the mistake is definitely with my understanding of pointers, so if you have any suggestions for a source I could use to study them all over I'd be quite thankful. Thanks in advance.

8
  • Yea, that one. I was supposed to learn C in a course next year (I'm a freshman in EE) but it doesn't fit my degree plan. It's the book that course uses. Commented Feb 15, 2014 at 0:33
  • Read chapter 11 and 12 carefully. He explained it very well. Commented Feb 15, 2014 at 0:34
  • I know yea, I've already read them 2 times so far but I guess it's because I always do that after 12+ hour days. Thank you. Commented Feb 15, 2014 at 0:36
  • scanf() is one of the trickier functions to use correctly; it is subtle and endlessly devious. Did you come up with the code in the question on your own? Using a pointer to an array is a non-trivial exercise, and I think your code should be compiling with some warnings about mismatched types (in the for line and in the scanf() line). Commented Feb 15, 2014 at 0:37
  • It's my own, yes. The compiler is giving me a bunch of warnings and I kept trying to fix them but I don't really understand the warnings, I'm just really confused about pointers. Commented Feb 15, 2014 at 0:40

1 Answer 1

4

Given the following code (derived rather closely from what you show in the question) in a file xx.c:

#include <stdio.h>

int main(void)
{
  enum { M = 4, N = 5 };
  int a[N][M];

  for(int (*p)[M] = &a[0][0]; p <= &a[N-1][M-1]; p++)
  {
    scanf("%d", p);
  }
  return 0;
}

The GCC 4.8.2 compiler (running on an Ubuntu 12.04 derivative) says:

$ gcc -g -O3 -std=c99 -Wall -Wextra -Werror -c xx.c
xx.c: In function ‘main’:
xx.c:8:21: error: initialization from incompatible pointer type [-Werror]
   for(int (*p)[M] = &a[0][0]; p <= &a[N-1][M-1]; p++)
                     ^
xx.c:8:33: error: comparison of distinct pointer types lacks a cast [-Werror]
   for(int (*p)[M] = &a[0][0]; p <= &a[N-1][M-1]; p++)
                                 ^
xx.c:10:5: error: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int (*)[4]’ [-Werror=format=]
     scanf("%d", p);
     ^
cc1: all warnings being treated as errors
$

The first error is because p is a pointer to an array of size M, but &a[0][0] is just a pointer to an int. The comparison failure is similar. You could write:

for (int (*p)[M] = &a[0]; p < &a[N]; p++)

That then leaves the scanf() error to be resolved. The trouble there is that you're passing a pointer to an array to a function that expects a pointer to an int. Further, because of the way array pointer increments work, you are attempting to read one number for the whole of one row of data. If you proceed down this path, you'd need a nested loop:

    for (int *q = &(*p)[0]; q < &(*p)[M]; q++)
        if (scanf("%d", q) != 1)
            ...process data format error...

On the other hand, you can simplify your life by using:

for (int *p = &a[0][0]; p < &a[N][M]; p++)
    if (scanf("%d", p) != 1)
        ...process data format error...

This is the route I'd recommend you take if you are required to use pointers (to int). Pointers to arrays are to be avoided as much as possible, which is almost all of the time.

The two variants are here encapsulated into one program, along with code using array indices (suggested by Jim Balter in a comment), which is much the simplest and hardest to get wrong:

#include <stdio.h>

extern void error(const char *msg);

int main(void)
{
  enum { M = 4, N = 5 };
  int a[N][M];

  // Pointers to arrays - nasty
  for (int (*p)[M] = &a[0]; p < &a[N]; p++)
  {
    for (int *q = &(*p)[0]; q < &(*p)[M]; q++)
    {
      if (scanf("%d", q) != 1)
        error("Bother");
    }
  }

  // Pointers to int - OK
  for (int *p = &a[0][0]; p < &a[N][M]; p++)
  {
    if (scanf("%d", p) != 1)
      error("Bother");
  }

  // Array indices - can't go wrong easily!
  for (int n = 0; n < N; n++)
  {
    for (int m = 0; m < M; m++)
    {
      if (scanf("%d", &a[n][m]) != 1)
        error("Bother");
    }
  }

  return 0;
}
Sign up to request clarification or add additional context in comments.

2 Comments

I'm only trying to do it in pointers because I was specifically told to, I already knew how to do it with indices and it's much easier. Thank you so much, it works perfectly and it helped me gain a better understanding of pointers.
One more thing to do is to use printf("name = %p", name); for various values of 'name' (e.g. for the pointers p or &(*p)[M]) to make sure you understand what values are being used. Also, printing p+1 (when p is a pointer to an array) may be insightful; you'll also print a, &a, &a[0], &a[0][0] and other variants on this theme. Draw pictures of the array a and make sure you understand how each of the loops works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.