Char array and 2D array pointer issues - c

This is part of an assignment to complete a word search. I have to use command line arguments to search a predetermined 2D array. I need to searh only the Horizontal (left to right), Diagnal (top-left to bottom-right), and Vertical (top to bottom).
I'll write the Diag and Vert once I understand the pointer issue better.
I get
warning: comparison between pointer and integer
This happens at the following if-statement
if (argv[count] == g[i][j]){
Why do I get the warning and what am I missing in my understanding of pointers that prevents me from doing this.
I've tried different variations of *g and (int star)g with worse results than just the warning.
I need to have warning free code for turn-in.
Thank You for helping the new people.
#include <stdio.h>
#define ROW 3
#define COL 4
#define TRUE 1
#define FALSE 0
int checkHoriz(char *data, char *data2);
main(int argc, char *argv[]){
int count, i, j, rowValue, colValue;
char g[ROW][COL] = {{'a','b','c','d'},
{'d','c','b','a'},
{'x','y','z','d'}};
count=1;
if(argc>1){
for(i=0; i<ROW; i++){
for(j=0; j<COL; j++){
if (argv[count] == g[i][j]){
rowValue = i;
colValue = j;
if(checkHoriz(argv[count],g[i][j]) ==TRUE){
printf("%s appears horizontally starting # g[%d]{%d]. \n", argv[count], i,j);
}
}
}
}
}else{
printf("No arguments were entered.\n");
}
}
int checkHoriz(char *data, char *data2){
int i = 0;
while (data == data2 && data!=' ' && data2 != '\0'){
data++;
data2++;
}
if(data2 == '\0'){
return 1;
}else{
return 0;
}
}

argv is an array of strings; a char** and g is an array of char arrays; a char[][].
Therefore, argv[count] is of type char* (a string), and g[i][j] is of type char. You're comparing a pointer to a single char, an integer type. This is what the warning is telling you.
If you want to search for the chars of g inside of argv[count], then you're going to need to dereference argv[count] one level further, and work with the individual chars in the range of argv[count][0] to argv[count][strlen(argv[count]) - 1].

Related

C: how to give 2D Array to a function

I want to pass a 2D array already filled with chars to a different method to do something with it.
Background: I am trying to implement GameOfLife. And I have already successfully implement the gameboard with a random amount of living cells. But now I want to pass the board(Array) to a different method to continue working with it. How to do so?
//wow das wird hurenshon
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void spielStarten(int x, int amountOfLiving){
char feld[x][x];
for(int i = 0; i < x; i++){
for(int j = 0; j < x; j++){
feld[i][j] = 'o';
}
}
for(int i = 0; i < amountOfLiving; i++){
int a = (rand()%x);
int b = (rand()%x);
feld[a][b] = 'x';
}
printf("Gameboard: \n");
for(int i = 0; i < x; i++){
for(int j = 0; j < x; j++){
printf("%c ", feld[i][j]);
}
printf("\n");
}
spielRun(feld);
}
void spielRun(char feld[][]){
int neighbCount;
char feldNew[][] = feld[][];
for(int i = 0; i < x; i++) {
for(int j = 0; j < x; j++) {
checkForNeighbours(feld[x][y]);
// in progress
}
}
}
int main(int argc, char* argv[]){
srand(time(NULL));
int x = 16;
if(argc < 2 || argc > 3){
printf("2. Argument eine Zahl fuer Feldgroesse eingeben\n");
printf("1. Argument eine Zahl 0-10 fuer ungefähre prozentuale Belegung mit lebenden
Zellen eingeben \n");
return 0;
}
if(argv[2] != NULL){
x = atoi(argv[2]);
}
int i;
i = atoi(argv[1]);
i = (x^2)*(0,1*i);
spielStarten (x,i);
return 0;
}
In the last line of the Method "Spiel starten" i want to give the array to the next Method "spielRun".
Edit: thanks to an other user I found this struture:
void printarray( char (*array)[50], int SIZE )
But it doesn't work for me since I can´t hardcode the number, because the arraysize depends on a user input.
thanks!
The difficulty here is that the size of your array is not known statically (once upon a time, your code would even not compile for the same reason).
That, combined with the fact that 2D-arrays are not arrays of 1D arrays (contrarily to what happen when you malloc a int ** and then every int * in it), and so it doesn't make sense not to specify the size when passing it to a function.
When using arrays of arrays (technically, pointers to a bunch of pointers to ints), like this
void f(int **a){
printf("%d %d %d\n", a[0][0], a[1][0], a[0][1]);
}
int main(){
int **t=malloc(10*sizeof(int *));
for(int i=0; i<10; i++) t[i]=malloc(20*sizeof(int));
f(t);
}
That code is useless, it prints only unitialized values. But point is, f understands what values it is supposed to print. Pointers arithmetics tells it what a[1] is, and then what a[1][0] is.
But if this 2D-array is not pointers to pointers, but real arrays, like this
void f(int a[][20]){
printf("%d %d %d\n", a[0][0], a[1][0], a[0][1]);
}
int main(){
int t[10][20];
f(t);
}
Then, it is essential that the called function knows the size (or at least all sizes, but for the first dimension) of the array. Because it is not pointers to pointers. It is an area of 200 ints. The compiler needs to know the shape to deduce that t[5][3] is the 5×20+3=103th int at address t.
So, that is roughly what is (better) explained in the link that was given in comments: you need to specify the size.
Like I did here.
Now, in your case, it is more complicated, because you don't know (statically) the size.
So three methods. You could switch to pointers to pointers. You could cast your array into a char * and then do the index computation yourself (x*i+j). Or with modern enough C, you can just pass the size, and then use it, even in parameters, declaration
void f(int x, int a[][x]){
printf("%d %d %d\n", a[0][0], a[1][0], a[0][1]);
}
int main(){
int t[10][20];
f(t);
}
Anyway, from an applicative point of view (or just to avoid segfault) you need to know the size. So you would have had to pass it. So why not pass it as first parameter (Note that the function in which you have this size problem, spielRun, does refers to a x, which it doesn't know. So, passing the size x would have been your next problem anyway)
So, spielRun could look like this (not commenting in other errors it contains)
void spielRun(int x, char feld[][x]){
int neighbCount;
char feldNew[][] = feld[][]; // Other error
for(int i = 0; i < x; i++) {
for(int j = 0; j < x; j++) {
checkForNeighbours(feld[i][j]); // Corrected one here
// in progress
}
}
}
And then calls to this spielRun could be
spielRun(x, feld);
Note that I address only the passing of array of size x here. There are plenty of other errors, and, anyway, it is obviously not a finished code. For example, you can't neither declare a double array char newFeld[][] = oldFeld[][]; nor affect it that way. You need to explicitly copy that yourself, and to specify size (which you can do, if you pass it).
I am also pretty sure that i = (x^2)*(0,1*i); does not remotely what you expect it to do.

Need to be "pointed" in the right direction beginning C programming

and thanks for your time. I apologize in advance I am new to C programming and posting on stack overflow. Any information I may have left out and questions you have please ask.
I have this lab I am working on for my class and I'm having trouble understanding how the dreaded pointers operate. First I will explain the lab instructions.
First, I am to create an array of 200 words with a max length of 30+1 for null.
Next, call functions I need to create which include:
A read function which reads words from a file into the array. I must use fopen and fscanf functions.
A function to convert a string to lowercase using the ASCII codes of each character. (Must use pointers)
A function to return the length of a string.(Can't use strlen function and must use pointers)
A function with three parameters(array of words, # of words in array, and an int length). Function returns the number words in the array that match the int length.
A print function to print all the words in the array.
The IDE I am using is Dev C++ its been wonky so I have also been using netbeans.
I have only attempted to create the read, print, and converting to lowercase functions. I first tried to read the file and print the array in main. The file I'm reading is created by me it contains a short sentence which follows exactly:
There ARE so MANY words in HERE
EDIT- Updated main code to current with working lowercase loop inside main.
#define rows 200 //How many words allowed in array.
#define cols 31 //How many characters allowed for each word.
void lowercase(char* words, int count);
int read(char (*words)[cols]);
void print(char (*words)[31], int count);
int main(int argc, char *argv[]){
char words[rows][cols];
int i, j;
int count = read(words);
print(words, count);
/*
//make words lowercase
for(i = 0;i<count;i++){
for(j = 0;j<cols;j++){
if(words[i][j]!=0){
if(words[i][j]<91 && words[i][0]>64)
words[i][j] = words[i][j]+32;
}
}
}*/
for(i = 0;i < count;i++){
lowercase(*words+i, count);
}
print(words, count);
return 0;
}
The code is poorly written and managed properly I'm just trying to get everything to work first then it will be more appropriate. The first printf output comes out how it should:
Array [0]: There
Array [1]: ARE
Array [2]: so
Array [3]: MANY
Array [4]: words
Array [5]: in
Array [6]: HERE
Then the print function I have prints out the words correctly in the array but it includes all 30 spaces for each word instead of just the word. This is how it is written I need to change it.
void print(void *array, int SIZE){
int i,
j;
char *charArray = (char *) array;
for( j = 0; j < SIZE; j++ ){
for( i = 0; i < SIZE; i ++){
printf( "%c ", charArray[j*SIZE + i] );
}
printf( "\n" );
}
}
The tolower function I created was partially working converting the first letter of each word to lowercase. Now it is broke and do not remember what I have changed.
EDIT- updated lowercase function. The lowercase in main works exactly but with this function it doesn't convert all the words to lowercase it stops at the third word the rest are the same.
void lowercase(char *words, int count){
int j;
for(j = 0;j<cols;j++){
if(words[j]!=0){
if(words[j]<91 && words[j]>64)
words[j] = words[j]+32;
}
}
}
I tried to move the read code in main to its own function also trying to mimic the print code with the pointers but when I run the program it stalls and the exe file stopped working window pops up with command prompt.
No errors or warnings in IDE.
int read(void *array){
FILE *file;
int i,
j;
char *words = (char *) array;
file = fopen("words.txt", "r");
//STORE IN ARRAY
for(i=0;i<7;i++)
fscanf(file,"%s", words[i]);
}
If you have not figured out I have no idea when or how to use pointers or addresses. I have been taught basically all of C in literally 12 hours which is in my opinion not enough time to learn the language at all especially understand it efficiently. Any help will be greatly appreciated. Thank You.
By casting a 2-dimensional array down to a char*, you have lost some information. If you read the words in correctly, then in memory, your array might look like this:
0 10 20 30
|.........|.........|.........|.
There
ARE
so
MANY
words
in
HERE
To access words[1] the compiler is automatically offsetting 31 bytes from the beginning of the array.
Your problem is that after you cast words to char*, then the compiler no longer knows about the 2D structure, and words[1] will now only offset 1 byte from the beginning of the array.
A simple solution is to redefine your read function:
int read(char words[][31])
{
FILE *file;
int i, j, count = 0;
file = fopen("words.txt", "r");
for (i=0; i<7; i++)
{
count += (1 == fscanf(file, "%s", words[i]));
}
return count;
}
Now the compiler knows that the memory stride size for words[i] is 31 char values.
Similar thing with print:
void print(char words[][31], int count)
{
int i;
for( i = 0; i < count; i ++)
{
printf( "%s\n", words[i] );
}
}
fix like this:
#include <stdio.h>
#include <stdlib.h>
//Stringification
#define S_(n) #n
#define S(n) S_(n)
//Information to be shared across the whole area
#define MAX_ROWS 200
#define MAX_WORD_LENGTH 30
#define COLS (MAX_WORD_LENGTH + 1)
#define DATA_FILE "words.txt"
int read(void *array);
void print(void *array, int rows);
int main(void){
char words[MAX_ROWS][COLS];
int rows;
rows = read(words);
print(words, rows);
return 0;
}
int read(void *array){
FILE *file = fopen(DATA_FILE, "r");
if(file == NULL){
perror("fopen:");
exit(EXIT_FAILURE);
}
char *words = array;
int rows;
for(rows = 0; rows < MAX_ROWS; ++rows, words += COLS){
if(fscanf(file, "%" S(MAX_WORD_LENGTH) "s", words) == EOF)
break;
}
fclose(file);
return rows;
}
void print(void *array, int rows){
char *words = array;
for(int r = 0; r < rows; ++r, words += COLS){
printf("Array [%d]: %s\n\n", r, words);
}
}

How to read command-line arguments as integers instead of strings?

Sorry for my question, I know there are a lot similars but I didn't found any that is simple enaugh to help me.
I've started coding in C and try to solve a simple exercise: Read an integers array from command line, sum the elements using the function array_sum and print result. (input example array of 3 elements: 3 0 1 2)
int array_sum(int *array, size_t size);
int main(int argc, char **argv){
int sum=array_sum(argv, argc);
printf("array_sum: %i\n", sum);
return 0;
}
my problem is that argv is a char array and the function want an integer array.
Should I convert elements one by one in a new int array? There are better ways?
argv is an array of pointers to C strings. You need to convert the strings into integers first. You can do something like this:
int array_sum(int *array, size_t size);
int main(int argc, char **argv){
int *num_arr = malloc((argc - 1) * sizeof *num_arr);
for (int i = 0; i < argc - 1; ++i)
num_arr[i] = atoi(argv[i+1]);
int sum = array_sum(num_arr, argc - 1);
printf("array_sum: %i\n", sum);
free(num_arr);
return 0;
}
The only way to make the code in main shorter is by moving the conversion loop into a separate function that returns the malloced pointer.
In your code, char *argv[] is an array of char* pointers supplied from the command line. In order to convert the numbers supplied, you can use the following:
atoi(), which converts string arguement to an integer type.
Or strtol(), which converts the initial part of a string to a long int, given a base.
Other special functions from C99, alot of which are described in this post.
Since atoi() has no error checking, it is best to use strtol(), which allows extensive error checking.
You should store these converted numbers in a dynamically allocated int* pointer, which will need to be allocated on the heap using malloc(), which was suggested by #StoryTeller in his answer. You could also just declare an array on the stack, such as int arr[n]. The problem arises when you want to return this array in a function, which is not possible. Using a pointer in this case would allow more flexibility for abstraction.
malloc()allocates block of memory on the heap, and returns a void* pointer to it.
Note: malloc() should always be checked, as it can return NULL. You need to also free() this pointer at the end.
Here is some example code:
#include <stdio.h>
#include <stdlib.h>
#define BASE 10
/* Guessed that your function would look like this */
int array_sum(int *array, size_t size) {
int sum = 0;
for (size_t i = 0; i < size; i++) {
sum += array[i];
}
return sum;
}
int main(int argc, char *argv[]) {
int *arr = NULL;
char *endptr = NULL;
int check, sum;
size_t ndigits = (size_t)argc-1;
/* allocate pointer */
arr = malloc(ndigits * sizeof *arr);
if (arr == NULL) {
fprintf(stderr, "Cannot %zu spaces for integers\n", ndigits);
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < ndigits; i++) {
/* sufficient checking for strtol(), more can possibly be added here */
check = strtol(argv[i+1], &endptr, BASE);
if (endptr != argv[i+1] && *endptr == '\0') {
arr[i] = check;
}
}
sum = array_sum(arr, ndigits);
printf("array_sum: %d\n", sum);
/* pointer is free'd */
free(arr);
arr = NULL;
return 0;
}
Example input:
$ gcc -Wall -Wextra -std=c99 -o sumcommands sumcommmands.c
$ ./sumcommands 3 2 1
Output:
array_sum: 6
Note: You can use more error checking for strtol() on the Man page.
Why do you need to pass an int array as argument to the function ? No need to create an extra int array when you can simply do this :
int array_sum(char **argv, int argc){
int sum = 0;
for(int i = 0;i < argc - 1;i++){
sum += atoi(argv[i])
}
return sum;
}
You can use atoi() function to convert char ** array to **int . what i see here is each integer you type is converting into string rather than char.

creating word search puzzle solver in c, Incompatible pointer type and pointer from integer without cast warnings in c

as the title says im attempting to create a program that searches through a 3x4 predefined grid for words that the user enters in the command line, i have the code completed but i am encountering these pointer warnings when i try to compile, the errors are as follow:
In function 'main':
59: warning: passing argument 1 of 'horizontalrow' makes pointer from integer without a cast
59: warning: passing argument 2 of 'horizontalrow' from incompatible pointer type
60: warning: passing argument 1 of 'verticalrow' from incompatible pointer type
60: warning: passing argument 2 of 'verticalrow' from incompatible pointer type
61: warning: passing argument 1 of 'diagonalrow' from incompatible pointer type
61: warning: passing argument 2 of 'diagonalrow' from incompatible pointer type
my code is as follows:
#include<stdio.h>
#include<string.h>
#define ROW 3
#define COL 4
void horizontalrow(char *a[ROW][COL], char *argv[], int argc)
{
int i=0,j=0, k =0;
for(i = 0; i < ROW - 1; i++){
for(j = 0;j < COL; j++){
for(k=0;k<argc;k++){
if(strcmp(a[i][j],argv[k])!=0){
printf("%s appears horizontally at a[%d][%d]", a[i][j],i,j);
}
}
}
}
}
void verticalrow(char *a[ROW][COL], char *argv[], int argc)
{
int i=0,j=0, k=0;
for(j = 0; j< COL - 1; j++){
for(i = 0; i < ROW; i++){
for(k=0;k<argc;k++){
if(strcmp(a[i][j], argv[k])!=0){
printf("%s found veritcally at a[%d][%d]",a[i][j],i,j);
}
}
}
}
}
void diagonalrow(char *a[ROW][COL], char *argv[], int argc)
{
int slice = 0, i = 0, j =0, z1 = 0, z2 =0, k=0;
for(slice = 0; slice < ROW + COL -1; slice++){
for(j = z2; j <= slice - z2; j++){
for(k=0;k<argc;k++){
if(strcmp(a[i][j],argv[k])!=0){
printf("%s is found diagonally at a[%d][%d]", a[i][j], i, j);
}
}
}
}
}
int main(int argc, char *argv[])
{
int i=0,j=0,k=0;
char a[ROW][COL] ={ {'a','b','c','d'},
{'d','c','b','a'},
{'x','y','z','d'}};
horizontalrow(a[ROW][COL],argv[k], argc);
verticalrow(a[ROW],argv[k], argc);
diagonalrow(a[ROW],argv[k], argc);
return 0;
}
There are too many errors in your code. Here's a working program to get you going in the right direction. I have removed verticalrow and diagonalrow to simplify things.
#include <stdio.h>
#include <string.h>
#define ROW 3
#define COL 4
void horizontalrow(char a[ROW][COL], char *argv[], int argc)
{
int i=0,j=0, k =0;
for(i = 0; i < ROW - 1; i++)
{
for(j = 0;j < COL; j++)
{
for(k=0;k<argc;k++)
{
if(a[i][j] == *argv[k] )
{
printf("%c appears horizontally at a[%d][%d]\n", a[i][j], i, j);
}
}
}
}
}
int main(int argc, char* argv[])
{
char a[ROW][COL] = { {'a','b','c','d'},
{'d','c','b','a'},
{'x','y','z','d'} };
horizontalrow(a, argv+1, argc-1);
return 0;
}
Changes made to your program
Signature of the function.
You had:
void horizontalrow(char *a[ROW][COL], char *argv[], int argc)
I changed it to
void horizontalrow(char a[ROW][COL], char *argv[], int argc)
// ^^^ no pointer, just the array.
You declaration expects the argument to be a two dimensional array of pointers to char. What you need is just a two dimensional array chars.
Comparing the command line arguments.
You had:
if(strcmp(a[i][j],argv[k])!=0){
I changed it to:
if(a[i][j] == *argv[k] )
Your code was syntactically correct but didn't make any sense semantically. My changes assume that the command line arguments you use to run the program are single character strings, such as
myprogram a b c
If you had a different idea for the command line arguments, you'll need to adapt the code.
Format specifier in printf.
You had:
printf("%s appears horizontally at a[%d][%d]", a[i][j],i,j);
I changed it to:
printf("%c appears horizontally at a[%d][%d]\n", a[i][j], i, j);
You had a syntactically valid format specifier. Since I changed the argument type, I had to change the format specifier too.
Removed unnecessary variables from main.
I removed the line
int i=0,j=0,k=0;
You don't need these variables.
Changed the syntax used to call the function.
You had:
horizontalrow(a[ROW][COL],argv[k], argc);
I changed it to:
horizontalrow(a, argv+1, argc-1);
Use of a[ROW][COL] as an argument calls the function by using the value obtained from evaluating a[ROW][COL]. It is syntactically wrong. The expected type of the function does not match the value type. The value type is char. Also, evaluation of a[ROW][COL] leads to undefined behavior since you are accessing the array out of bounds. The valid range of indices to access a are a[0][0] through a[ROW-1][COL-1].
It's not clear to me what you were hoping to pass to the function by using argv[k]. The value type of argv[k] does not match the argument type of the function. You can read more about using command line arguments at http://en.cppreference.com/w/c/language/main_function. Hopefully when you have finished reading that page, you will understand why I am using argc-1 as the third argument to horizontalrow.

how to manually concat a char **args to char *args

so I'm trying to write a function that concats a char**args to a char*args
What I have so far is":
char *concat(char **array)
{
int size = 0;
int i=0;
int j=0;
int z=0;
while (array[i]!=NULL)
{
printf(" %s \n", array[i]);
size = size + sizeof(array[i])-sizeof(char); //get the total size, minus the
//size of the null pointer
printf("%d \n",size);
i++;
}
size = size+1; //add 1 to include 1 null termination at the end
char *newCommand = (char*) malloc(size);
i=0;
while(i<sizeof(newCommand))
{
j=0;
z=0;
while (array[j][z]!='\0')
{
newCommand[i] = array[j][z];
i++;
z++;
}
j++;
}
newCommand[sizeof(newCommand)-1]='\0';
return newCommand;
}
this doesn't seem to work. Anyone know what's wrong?
I'd do it like this (untested):
int size = 0;
int count = 0;
while (array[count]) {
size += strlen(array[i]);
count++;
}
char *newCommand = malloc(size + 1);
char *p = newCommand;
newCommand[0] = 0; // Null-terminate for the case where count == 0
for (int i = 0; i < count; i++) {
strcpy(p, array[i]);
p += strlen(array[i]);
}
First, your size calculation was wrong. You wanted the size of the strings, but sizeof(array[i]) gives you the size of a single element in your array which is a pointer and thus 4 (32-bit) or 8 (64-bit). You need to use strlen instead.
Next, your manual copying was also off. It's easier to do it with a moving pointer and strcpy (which is to be avoided normally but we've calculated the sizes with strlen already so it's OK here). The use of strcpy here also takes care of null termination.
Main issue is that you keep using sizeof() with a pointer argument, whereas I think you are trying to get the size of the corresponding array.
sizeof() can only give you information that's available at compile time, such as the sizes of raw types like char and int, and the sizes of arrays with a fixed length such as a char[10]. The sizes of the strings pointed to by a char* is only computable at run time, because it depends on the exact values passed to your function.
For sizeof(newCommand) you probably need size, and for sizeof(array[i]), you probably need strlen(array[i]).

Resources