In order to solve your problem, you need to think about your game in terms of different "spaces".
First, lets talk about "worldspace". If you pretend that you have an suitably wide and tall device upon which you can do your rendering, you can render the entire grid of cells.
For a more concrete example, if your grid is 100x100 cells, and each cell is 16x16 pixels, you'd need a screen that is 1600x1600 pixels.
If you had such a device, you could easily render the whole thing.
You don't, which is why you are here. The device is only a particular number of pixels wide and tall. This is your "devicespace". A smartphone screen will have a different devicespace than a tablet.
If you are ONLY dealing with scrolling, then you need only keep track of a single point that maps one corner (typically the upper left corner) of devicespace into worldspace. This is an anchor point.
If using something like OpenGL, you can accomplish this quite easily with matrices, but knowing how to do in using just 2d algebra doesn't hurt either.
When you are scrolling around the worldspace, you simply change the anchor point, and re-render the area covered by devicespace, not the whole world (that would be wasteful). Fortunately, with a square grid, it is pretty easy to determine which grid cells need to be rendered, since you take the anchor point, divide by the cell height and widths, and start rendering there, stopping at the opposite corner.
The anchor point has some definite bounds. If it is (0,0) and the upper left corner is being used, the lower right corner is at (devicewidth,deviceheight).
When scrolling, the anchor point needs not go further than (worldwidth-devicewidth,worldheight-deviceheight), and so as a result, this and (0,0) are the bounds for a different type of space called "anchorspace".
To add zooming, there is slightly more to it, but it builds off of the basics here, there is simply one more intermediate space, but for now I'll leave you with the basic of scrolling.