passing two 2-d arrays into a function for comparison - c

I have been trying to pass two arrays into a function so that I can compare them but I am having trouble with the syntax of how to pass the arrays and begin to compare the rows. I am getting errors such as incompatible pointer types pass to type const char???? here is the code I have so far...im having trouble in the top sort function
//
#define MAXROWS 30
#define MAXCOLS 100
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char topsort( char, int, char, int);
int main(int argc, const char * argv[])
{
//array for all of the word's in the file
char list[MAXROWS][MAXCOLS], line[MAXCOLS], constraint[MAXROWS][MAXCOLS];
FILE *list_sort;
int listcols = 0, listrows = 0, concols = 0, conrows = 0;
//open the sequential access file and make sure its found
list_sort = fopen("/Volumes/JENN/cpma stuff/introcompsys/list sort.txt","r");
if(list_sort == NULL){
printf("can't open file");
exit(EXIT_FAILURE);
}
while(fgets(line, sizeof(line), list_sort) != NULL)
{
if(index(line, ',') == NULL){
for(listcols =0; listcols< strlen(line)-1 ;++listcols) {
list[listrows][listcols] = line[listcols];
}
list[listrows][listcols] = '\0';
printf("%s\n", list[listrows]); //print each row of the list to check
++listrows;
}
else{
for(concols =0; concols< strlen(line)-1 ;++concols) {
constraint[conrows][concols] = line[concols];
}
constraint[conrows][concols] = '\0';
printf("%s\n", constraint[conrows]); //print each row of the constraint to
//check
++conrows;
}
}
}
char topsort( char s1[][MAXCOLS], int listrows, char s2[][MAXCOLS], int conrows){
char sorted[MAXROWS][MAXCOLS];
while(the constraint array is not empty){ //pseudocode
int second = char *strchr(s2, ‘,’+ 2);
for(int i = 0; i < listrows ; i++){
for(int j = 0; j < conrows; j++){
strcspn(s2[j][second], s1[i]);
}
}
}
}

Multiple problems with topsort. It's not going to work.
This is a bad idea:
char s1[][MAXCOLS]
Either specify all the dimension sizes, or use char **.
This is wrong, for several reasons.
int length = strlen(s2[][]);
You don't give any array indexes, you're passing a char to a function that takes a char *, and you are using length in a while loop and never changing it.
strlen(&s1)
This is passing a char * * * to a function expecting a char *.
strcspn(s2[i], s1[i]);
passing two chars to a function that takes a char and a char *. Plus you don't even see the result.

Related

How do I get the number of elements a char array points to?

I was researching but could not find a way. I am passing 2 char array pointers to a function and fill those 2 arrays with values. Is there a way to get the size of the filled arrays?
I tried size_t size = sizeof(*arguments)/sizeof(arguments[0]) already but that gave me 1 as a result, I know why its giving me 1 as result by researching but I just couldn't find a way to get the proper array length(the value how much elements are in the array). If that is not possible how can I work around this ? I need to know this because, I wanna give the last value of any array a NULL for my exec functions.
My programs works as follows:
An user inputs 2 program names which are executed.
But the 2 programs are separated by a ";". So I have 2 arrays which can vary in size , which depends on the input in the terminal.
void getArguments(char * [],char * [], int ,char * []);
int main(int argc, char * argv[]){
pid_t pid,pid2;
char * arguments2[argc/2+1];
char * arguments[argc/2+1];
getArguments(arguments, arguments2,argc,argv);
if((pid=fork())==-1){
printf("Error");
}
else if(pid == 0){
execvp(arguments[0],arguments);
}
else{
if((pid2 = fork())== -1){
printf("Error" );
}
else if(pid2 == 0 ){
execvp(arguments2[0],arguments2);
}
else{
int status;
wait(&status);
exit(0);
}
}
return 0;
}
void getArguments(char * arguments[], char * arguments2[],int argc, char * argv[]){
int i=0;
while(strcmp(argv[i+1],";")!=0){
arguments[i] = argv[i+1];
i++;
}
arguments[argc/2-1]= NULL;
int j = i+2;
int k = 0;
for( ;j<=argc; j++){
arguments2[k] = argv[j];
k++;
}
arguments2[argc/2-1]=NULL;
}
No, you can't get the size of an array if you only have a pointer. You must pass the size as a separate argument to your function.
EDIT: I now understand you need to return from your function the number elements used in the array. You can either add two integer pointer variables that receive the size, or you could set the first unused element to NULL so the caller knows when it is at the end of the filled portion.
For example:
char * arguments2[argc]; // as you don't know the result, do not divide by 2: it may be too small!
char * arguments[argc];
int size1=0, size2=0;
getArguments(arguments, &size1, arguments2, &size2, argc, argv);
And:
void getArguments(char *arguments[], int *size1, char *arguments2[], int *size2, int argc, char *argv[])
{
// ...
*size1= i;
//...
*size2= j;
}

Segmentation fault after while loop that follows malloc

I am trying to create a 2d array dynamically, then open a txt file and copy each lenient my 2d array. Then save this array back to my main. I keep running into a segmentation error. Any suggestions how to do fix this code?
BTW i think the problem stars after the 2nd time while loop occurs...
#include<stdio.h>
char **randomArrayofStrings(){
char **twoArray=null;
int rows=50;
int col=20;
i=0;
FILE *file=null;
int messageSize=50;//this is number is trivial
file = fopen("somefile.txt","r");
twoArray= malloc(rows*sizeof(char*));
for(i=0;i<col;i++)
{
twoArray[i]=malloc(rows*sizeof(char));
strcpy(twoArray[i], "some random word");
}
while(!feof(file))
{
fgets(dArray[i],messageSize, file);
strtok(dArray[i], "\n");
i++;
}
return twoArray;
}
int main(int argc, char **argv)
{
char **localArray=null;
localArray=randomArrayofStrings();
for(i=0;i<20;i++)//20 is just a random number
printf("Strings: %s", localArray[i]);
}
As I see, in your function randomArrayofStrings loop for goes through columns "i cols in your code. So, you allocate array of pointers first and consider it as cols and then in a loop you allocate rows.
And after malloc check the value that was returned and do not use the pointer if it is NULL after memory allocation.
To free allocated memory, use the inverted sequence - free all rows in a loop and than free cols once. E.g.:
for(i=0;i<col;i++){
free(twoArray[i]);
}
free(twoArray);
twoArray = NULL;
EDIT:
And also, to use malloc and free you need #include <stdlib.h>, and #include <string.h> for strcopy, int i=0; should be instead of i=0;, and correct null value for pointers is NULL.
And what is dArray? I do not see the declaration or definition? Dou you mean twoArray?
EDIT2:
The following is my version of your program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **randomArrayofStrings(){
char **twoArray=NULL;
char * ptr = NULL;
int rows=50; // this will be also message size
int cols=20;
int i=0;
FILE *file=NULL;
file = fopen("somefile.txt","r");
if( file == NULL )
return NULL;
twoArray = (char**) malloc(cols * sizeof(char*));
if(twoArray == NULL)
{
return NULL;
}
for(i=0;i<cols;i++)
{
twoArray[i] = (char*)malloc(rows*sizeof(char));
if(twoArray[i] == NULL)
return NULL;
strcpy(twoArray[i], "some random word");
}
i = 0; // reset counter
while(!feof(file))
{
fgets(twoArray[i], rows, file);
ptr = strchr(twoArray[i],'\n');
if( ptr )
*ptr = '\0';
else
twoArray[i][rows-1] = '\0';
i++;
if( i >= cols)
break;
}
fclose(file);
return twoArray;
}
void freeMy2dArray(char **twoArray, int n)
{
int i;
for(i=0; i < n; i++){
free(twoArray[i]);
}
free(twoArray);
twoArray = NULL;
}
int main(int argc, char **argv)
{
int i;
char **localArray=NULL;
localArray = randomArrayofStrings();
if( localArray == NULL )
return 1;
for(i=0;i<20;i++)//20 is just a random number
printf("Strings: %s\n", localArray[i]);
freeMy2dArray(localArray, 20);
}
You are not suppossed to free() twoArray inside randomArrayofStrings(). You have to free them inside main(), once you're done with using the allocated memeory.
That said, the way you're using sizeof(localArray) in main() is wrong. You have to use the exact value you did use to poupulate twoArray.

Changing strings to upper within a double pointer array

I need to convert arguments given at command line such as: $ myprogram hello world
and the words need to be printed in CAPS. I am able to to do everything except access the double pointer array to make the changes with toupper()
static char **duplicateArgs(int argc, char **argv)
{
char **copy = malloc(argc * sizeof (*argv));
if(copy == NULL){
perror("malloc returned NULL");
exit(1);
}
int i;
for(i = 0; i<argc; i++){
copy[i] = argv[i];
}
char **temp;
temp = &copy[1];
*temp = toupper(copy[1]);
return copy;
}
*temp = toupper(copy[1]);
toupper converts a single character, if you want to convert an entire string:
char *temp = copy[1]; /* You don't need a double pointer */
size_t len = strlen(temp);
for (size_t i = 0; i < len; i++) {
temp[i] = toupper(temp[i]);
}
I assume the argument that is passed into your function char **argv is passed directly from main, so it represents a pointer to the beginning of an array of pointers to each of the command line arguments.
argc represents the number of command line arguments.
Inside your function, you create a new buffer, and then copy the contents of argv into it. So you are creating a copy of the array of pointers to the command line arguments, NOT the command line argument strings themselves.
I am guessing you intended to copy the strings, rather than the pointers to the strings (what would be the point of that?). I suggest you look into the functions strdup and/or strncpy to copy the actual strings.
This also explains with the 'toupper' does not work as you expect - instead of passing a single character to it, you are passing a pointer to a null terminated string of characters.
From the man page of toupper() the function prototype is
int toupper(int c);
In your code, the argument copy[1] is not an int value.
Instead what you want is to check each and every element, if they are in lower case, convert them to upper case. A pseudo-code will look like
for(i = 0; i<argc; i++){
copy[i] = malloc(strlen(argv[i])+ 1); //allocate memory
for (j = 1; j < argc; j++)
for (i = 0; i < strlen(argv[j]); i++)
{
if (islower(argv[j][i])) //check if it is lower case
copy[j-1][i] = toupper(argv[j][i]);
else
copy[j-1][i] = argv[j][i]; //do not convert
}
Consider this example:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
static char **duplicateArgs(int argc, char **argv)
{
char **copy = NULL;
// allocate memry for pointers to new lines
copy = (char **)malloc(sizeof(char *) * argc);
int line, chr;
for(line = 0; line < argc; line++)
{
// allocate memory for new line
copy[line] = (char *)malloc(sizeof(char) * (strlen(argv[line]) + 1));
// copy with changes
for(chr = 0; chr <= strlen(argv[line]); chr++)
{
copy[line][chr] = toupper(argv[line][chr]);
}
}
return copy;
}
int main(int argc, char * argv[])
{
char ** strs;
int i;
strs = duplicateArgs(argc, argv);
for(i = 0; i < argc; i++)
{
printf("%s\n", strs[i]);
}
return 0;
}
EDIT:
Also you can make a decision about using argv[0] (name of executable file) and change a code if you need. Also checking of malloc result can be added, and other improvements... if you need :-)
You are running into an error using the toupper() function because you are trying to pass in a string instead of an individual letter. Here is an excerpt from the man page describing the function:
DESCRIPTION
The toupper() function converts a lower-case letter to the corresponding
upper-case letter. The argument must be representable as an unsigned
char or the value of EOF.
You have a pointer to a pointer which you could visulize as something like this. In C a string is just an array of chars so you need to dereference twice to get the data in the second level of arrays (the individual letter). Every time you add an * you can think of it as removing one layer of pointers. And you can think of the * operator as the inverse of the & operator.
This line is your problem line
temp = &copy[1];
try this instead
//This is a pointer to an individual string
char *temp = copy[1];
//Keep going while there are letters in the string
while(*temp != NULL) {
//convert the letter
toupper(*temp);
//Advance the pointer a letter
temp++;
}

Return char array??(C)

I'm new at programming. I have:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // With luck, this declares strdup()
enum { ROWS = 50 };
static char *funkc(FILE *fp,char file[50])
{
int q,row;
char charbuffer[2],ch,*map[ROWS];
ch=getc(fp);
q=1;
while (ch!=EOF){
ch=getc(fp);
q++;
}
for (row = 0; row <=q; row++){
map[row] = " ";
}
fp = fopen(file, "r");
for (row = 0; row <= q; row++) {
if (fgets(charbuffer, 2, fp))
map[row] = strdup(charbuffer);
}
for (row = 0; row <= q; row++) {
printf("%s", map[row]);
}
return map[3];
}
int main(void)
{
char *map2[ROWS];
FILE *fp;
char file[50]; // Unused variable *map[ROWS];
printf("file name \n");
scanf("%s",file); // Removed ampersand from file
if ((fp=fopen(file,"r"))==NULL)
{
printf("Error \n");
exit(1);
}
map2[0]=funkc(fp,file);
printf("%s",map2[0]); // Add missing semicolon
return 0;
}
With that I can return only single char but I need to return full char array (map[ROWS]); how can I do it?
I think there are some problems in your code.
First, how can you use this piece of code?
scanf("%s", &file);
I think what you need to do is this one:
scanf("%s", file);
Because the array name file is a pointer itself, you don't need to use &.
Second, you can get an array of chars by return map[0], because it is a char * type, namely a string in C. Think about it.
If you pass an array to a function, any changes made to that array in the function will be accessible by your main function. This means that you don't have to return the array, just modify your array in funkc and main will see the new array.
In C, most variables are passed by value. If a variable's value is modified in a function, the new value will not be accessible elsewhere in the program. However, arrays are passed by reference, so funck has access to the array's memory. See here for more information:
http://staff.um.edu.mt/csta1/courses/lectures/csa2060/c6.html
Not reading your code thoroughly,
But your main problem is quite clear,
you need to study more about: pass by address, array, pointer.
Below are my very simple code to pass array for function and return to main.
You either pass by adress(array itself is), or pass a malloced pointer(remeber to free).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int test(char *map)
{
strcpy(map, "hello, world");
return 0;
}
int main(int argc, char **argv)
{
char map[20];
//char *map = malloc(sizeof(char) * 20);
test(map);
printf("%s\n", map);
//free(map);
return 0;
}
Two things you need to do, besides fixing other errors in the code:
You are expecting to get an array of strings, which would be char** type.
You also need to allocate memory for an array, as returning automatic variable reference is not a good idea. Also you need to allocate memory for every entry in the array, as mixing static string references and allocated memory is not a good idea either.
include ...
enum { ROWS = 50 };
static char **funkc(FILE *fp)
{
long fileSize = 0;
int row;
char **map = NULL;
map = (char**)calloc(ROWS, sizeof(char*));
fseek(fp, SEEK_END, 0);
fileSize = ftell(fp);
fseek(fp, SEEK_SET, 0);
for (row = 0; row < fileSize && row < ROWS; row++)
{
char buffer[2];
buffer[0] = fgetc(fp);
buffer[1] = 0;
map[row] = strdup(buffer);
}
for (;row < ROWS; row++)
{
map[row] = strdup(" ");
}
return map;
}
int main(int argc, const char *argv[])
{
char **map;
FILE *fp;
char fname[50];
int row;
printf("file name \n");
scanf("%s", fname);
fp = fopen(fname, "r");
map = funkc(fp);
fclose(fp);
for (row = 0; row < ROWS; ++row)
{
printf("ROW[%d]: %s\n", row, map[row]);
}
for (row = 0; row < ROWS; ++row)
{
free(map[row]);
}
free(map);
return 0;
}

Null terminating char pointer

I am completely newbie in C.
I am trying to do simple C function that will split string (char array).
The following code doesn't work properly because I don't know how to terminate char array in the array. There are to char pointers passed in function. One containing original constant char array to be split and other pointer is multidimensional array that will store each split part in separate char array.
Doing the function I encountered obviously lots of hustle, mainly due to my lack of C experience.
I think what I cannot achieve in this function is terminating individual array with '\0'.
Here is the code:
void splitNameCode(char *code, char *output);
void splitNameCode(char *code, char *output){
int OS = 0; //output string number
int loop;
size_t s = 1;
for (loop = 0; code[loop]; loop++){
if (code[loop] == ':'){
output[OS] = '\0'; // I want to terminate each array in the array
OS ++;
}else {
if (!output[OS]) {
strncpy(&output[OS], &code[loop], s);
}else {
strncat(&output[OS], &code[loop], s);
}
}
}
}
int main (int argc, const char * argv[]) {
char output[3][15];
char str[] = "andy:james:john:amy";
splitNameCode(str, *output);
for (int loop = 0; loop<4; loop++) {
printf("%s\n", output[loop]);
}
return 0;
}
Here is a working program for you. Let me know if you need any explanation.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void splitNameCode(char *code, char **output) {
int i = 0;
char* token = strtok(code, ":");
while (token != NULL) {
output[i++] = token;
token = strtok(NULL, ":");
}
}
int main (int argc, const char *argv[]) {
char* output[4];
char input[] = "andy:james:john:amy";
splitNameCode(input, output);
for (int i = 0; i < 4; i++) {
printf("%s\n", output[i]);
}
return 0;
}
If I understand your intent correctly, you are trying to take a string like andy:james:john:amy and arrive at andy\0james\0john\0amy. If this is the case, then your code can be simplified significantly:
void splitNameCode(char *code, char *output){
int loop;
strncpy(code, output, strlen(code));
for (loop = 0; output[loop]; loop++){
if (output[loop] == ':'){
output[loop] = '\0'; // I want to terminate each array in the array
}
}
}

Resources