Reassign values of multidimensional char array in C - arrays

I have an array of strings in C:
char taula[15][15];
This table is filled with the sentences of a file. The maximum letters a word can have is 15. The maximum words a phrase can have is also 15. This is its content:
{ "may", "the", "force", "be", "with", "you." }
Now, I need to change the order of the words so they are not in this order (but that doesn't matter for the question).
I am new to C, and what my brain has though is this (this is what I would do in Java):
char aux[15] = "";
char frase_nova[15][15];
for(i=0;i<15;i=i+2) {
aux = taula[i];
taula[i] = taula[i+1];
i++;
}
I create an aux variable to store a word, and create a new array to store the disordered phrase. I store the 1st element to the aux variable. Assign the 0th element to the 1st, and finally I assign the aux to the 0th element, and so on. This way I should get this phrase as result:
the may be force you. with
This has caused me an error, so I searched why, and I changed that code to this code, using strcpy:
strcpy(aux,frase_nova[i+1]);
strcpy(frase_nova[i+1],frase_nova[i]);
strcpy(frase_nova[i],aux);
printf("%s",frase_nova[i]);
But this causes me a strange result. Something that I don't understand is happening with the pointers and the arrays or whatever it is.
the E�Ube you.��aE�URE�U
So I would like to know how to fill a new multidimensional char array with values of an original multidimensional char array in the order ([i]) I want.

The maximum letters a word can have is 15.
Then you should have size of words, in 2D char array, as 16 and not 15
char taula[15][16];
^^
because, in C, strings are actually one-dimensional array of characters terminated by a null character '\0'. Hence, you need space to accommodate null character '\0'.
Your array has 6 strings i.e. 3 pairs, so you need iterate loop only 3 times. But, looks at this for loop:
for(i=0;i<15;i=i+2) {
it will iterate for more than 3 times. May you can keep track of number of elements in your 2D array and use it instead of 15 in the loop condition.
As you understood that these statements, of for loop body, won't work:
aux = taula[i];
taula[i] = taula[i+1];
because both aux and taula are arrays. But there is one more problem in your loop body and which is this statement:
i++;
You are already incrementing i in loop - i=i+2 and if you do i++ in loop body then, in every iteration, i will be incremented by 3 and which will not give the desired results. You don't need to do i++ in loop body.
There is no problem with these statements:
strcpy(aux,frase_nova[i+1]);
strcpy(frase_nova[i+1],frase_nova[i]);
strcpy(frase_nova[i],aux);
printf("%s",frase_nova[i]);
provided
if the array frase_nova has elements { "may", "the", "force", "be", "with", "you." }, and.
loop variable i is incremented twice only in every iteration.
Check the following code:
#include <stdio.h>
#include <string.h>
#define WORDS 15
#define WORD_SZ 16
#define NUM_ELE 6
int main(void) {
char frase_nova[WORDS][WORD_SZ] = { "may", "the", "force", "be", "with", "you." };
char aux[WORD_SZ] = "";
for(int i = 0; i < NUM_ELE; i = i + 2) {
// using your posted statements as it is
strcpy(aux, frase_nova[i + 1]);
strcpy(frase_nova[i + 1], frase_nova[i]);
strcpy(frase_nova[i], aux);
printf("%s ", frase_nova[i]);
}
printf ("\n");
for (int i = 0; i < NUM_ELE; ++i) {
printf ("%s ", frase_nova[i]);
}
printf ("\n");
return 0;
}
Output:
# ./a.out
the be you.
the may be force you. with
So I would like to know how to fill a new multidimensional char array with values of an original multidimensional char array
This is not clear whether you want to fill the new multidimensional char array with the values of original multidimensional char array before swapping the strings of original array or after swapping the strings. But, whatever you want, you can simply achieve it by doing this - strcpy(frase_nova[i], taula[i]).

To swap 6 words you need to iterate 6 times, not 15 times. Unless you simply wish to shuffle words around according to some strange pattern.
Also the loop doesn't make any sense. I don't understand why you do i=i+2. Also any loop of the nature for(int i=0; i<n; i++) can never access item array[i+1] in the loop body, because that leads to out of bounds access.

Related

How to count how many elements have been added to an array in C

So basically I have an array with a size of 5 and I want to count how many elements it has inside it.
int main()
{
int size;
char ola[5];
ola[0] = 'p';
size = sizeof(ola);
printf("%d\n", size);
return 0;
}
This code returns 5, but I expected 1.
What should I change?
The C standard does not provide any usable concept of elements in an array being used or unused. An array is simply a sequence of elements. It is up to you to track how many elements in it are of interest to you; you must write your own code for this.
You can do this by keeping a separate counter, by using a particular element value to denote that an element is “unused,” by using a particular element value to denote that an element ends the elements of interest, by calculating the end from related information, or by other means.
The C library includes many routines that use the third method, where the “null character,” with value zero, is used to mark the end of a string of characters. When you use this method, be sure to include room for the terminating null character in any array. For example, if you want an array to hold strings of length up to n characters, define the array to have at least n+1 elements.
Keep a count as you add elements to the array, rather than using sizeof (which returns the total capacity of the array in bytes), for example
#include <stdio.h>
int main(void)
{
int size = 0; // initialize size
char ola[5] = ""; // also initialize ola (with 5 '\0's)
ola[size++] = 'p'; // use and increment size
// size = sizeof(ola); // size is already updated
printf("%d\n", size);
// one more character
ola[size++] = 'o';
printf("%d\n", size);
printf("The string is [%s]\n", ola);
return 0;
}
It returns 5 because it is the size of your array, you could try:
size = sizeof(ola[0]);
To get the response 1, this mean that you are getteing exatly the size of the element, and not the size of whole array.

Comparing elements from two 2d-arrays in C without strcmp

I am creating a spell-checker in C. I have a dictionary array which is a 2d array. So each word in the dictionary takes a row in the 2d array. In the same way, my input array is also a 2d array. I want to check the spelling of the rows/words in my input array. I cannot use strcmp
An example of input array
['boy','girll','.','friend',' ']-can contain spaces,punctuation and words. We only care about spelling words
if a punctuation/space is compared against a word,we ignore it and move onto the next word.
example of dictionary
['boy','girl','cow'...]-all are words
My code is:
for (int a = 0; a < MAX_INPUT_SIZE + 1; a++)
{
for (int b = 0; b < MAX_DICTIONARY_WORDS; b++)
{
if(tokens[a]==dict_token[b])
{
printf("correct");
}
else
{
printf("wrong");
}
}
}
The output is all "wrong". Though 5 out of the 6 word input should be correct.
Every test returns false because the comparison you're using,
if(tokens[a]==dict_token[b])
is comparing two pointers that are never going to point at the same address, because, the tokens you are testing are in a completely separate bit of memory to the dict_token dictionary that you are comparing them with.
You need to pass the two pointers tokens[a] and dict_token[b] to a comparison function that will perform a letter-by-letter comparison, and which will return one value when it finds a difference between them, and another when it gets to the end of both without finding a difference. In other words, you need to write an implementation of strcmp.

How can I map a character to a pointer of another type?

I have a char*. I want to parse it, character by character, and store the location of each in an int*.
With the dummy-string "abbcdc", the content should be as follows
char int*
-------------
'a' -> 0
'b' -> 1,2
'c' -> 3,5
'd' -> 4
I want this to be accessible through a char* containing the entire alphabet, so that each character in the alphabet-pointer points to each separate integer-pointer. This is where I'm lost.
I know I can point to a pointer using the double-asterisk syntax
int **a = &aLocations;
But I don't really know how to refer to the locations-pointer by using a character as a reference. I am pretty new to C, so all pointers (pun intended) are appreciated.
Update 1:
int *aLocations = malloc(3*sizeof(int));
aLocations[0] = 13;
aLocations[1] = 9;
aLocations[2] = 57;
int **a = &aLocations;
This seems to work as expected, but a obviously remains an integer, not a char. I was thinking of writing a function something along the lines of
int *getCharLocations(char c) {
// returns a pointer to the stored character locations
}
but I don't know how to proceed with implementing it.
Ok then.
Although it would be possible it would be pretty ugly and complicated.
So if you do not mind i would suggest to drop char and use integers exclusively.
It is possible since char is in fact just small integer.
So first you would need to create your two dimensional alphabet array:
int *alphabet[26]; // this will create 26 element array of integer pointers
Now we will fill it:
int i = 0;
for(i = 0; i < 26; i++) {
alphabet[i] = malloc(100 * sizeof(int)); //alloc memory for 100 integers (should be enough for human language if we're talking about single words here)
alphabet[i][0] = 'a' + i; // this will put a letter as first element of the array
alphabet[i][1] = 2 // here we will keep index of first available position in our indices array
}
So now we have array like this:
'a', 2, ... // '...' means here that we have space to fill here
'b', 2, ...
...
'z', 2, ...
And you can add indices of occurences of letter to such construction like this:
alphabet[index_of_letter][alphanet[index_of_letter][1]] = index_of_letter; //put index at the end of array
alphabet[index_of_letter][1]++; // increment our index of available position
That's pretty much it.
I didn't test it so it may need some polishing but such approach should do the trick.
PS.
Someone in comments above noted uppercase letters - in such case you would need to extend array to 52 characters to store also occurences of uppercase letters (also fill first element with uppercase letter in for loop for such records). But i guess you will manage from now on

This code return wrong first pointer in a array of pointers

This is my code
#include <stdio.h>
int main()
{
char *fruit[] = {
"Water",
"banana",
"pear",
"apple",
"coconut",
"grape",
"blueberry"
};
int x;
int g;
for(x=0;*(fruit+x)!='\0';x++)
{
for (g=0; *(*fruit)++; g++)
{
putchar(*(*(fruit+x)+g));
}
putchar('\n');
}
return(0);
}
And this is what the code returns...
aeaa
banana
pear
apple
coconut
grape
blueberry
Program ended with exit code: 0
I don't understand what I'm doing wrong... Why the first point goes wrong and the others pointers display as I expect.
Can anyone please explain? I'm using Xcode.
To understand what is going on you should place a breakpoint on your first for line, run the code till it stops and then step through watching the values of fruit, x & g. If you do this you'll notice something strange - after the first time around the outer loop the first element of fruit changes to banana (the remaining entries stay the same, so you now have two bananas).
Do this now and watch. If you can't use the debugger stop now and figure it out.
So what is happening?
First let's look at what your code outputs:
ae?aa (? is actually upside down on my run)
banana
etc.
Where could those characters be coming from? Well if the compiler packs your strings into memory, remembering that each string ends in a null byte which we will represent by ? then packed into memory you have:
Water?banana?pear?apple
etc. Your program is printing out 5 characters, the number in Water, and they are the 2nd, 4th, 6th, 8th and 10th in memory...
So now we know what we're seeing, why are we seeing it?
Let's look at fruit, it is a 1-dimensional array of char * - pointers into memory containing the characters in the strings. If we look at the first few pointers in this array when I run your code they are (actual values may differ):
0x100000e24
0x100000e2a
0x100000e31
Looking at just the last two digits, and converting from hexadecimal, we have 36, 42, 49. The first difference is 6, the number of bytes needed to store "Water" (including the trailing null byte), the next is 7, the number of bytes needed to store "banana", and so it goes on.
Now let's look at your first for loop:
for(x=0; *(fruit+x) != '\0'; x++)
Now *(fruit+x) is the same as writing fruit[x], so in each iteration of the loop you are looking at an element of fruit starting with the first (index 0). Now fruit contains values of type char * but you are comparing the value to a char - they are not the same thing!
When C constructs an array with unspecified bounds (the empty [] in the declaration of fruit) from a literal as you've done here it does not add anything after the last element of the array to indicate there are no more elements. There are two common ways to deal with this: you can calculate the number of elements using two calls to sizeof (see #Lundin's answer); or you can use a sentinel - a value which will not occur in the array otherwise. For arrays of pointer values the standard sentinel is NULL - the pre-declared pointer to nothing. So to make this part of your code work we change the code to:
char *fruit[] =
{
"Water",
"banana",
"pear",
"apple",
"coconut",
"grape",
"blueberry",
NULL
};
int x;
int g;
for(x=0; *(fruit+x) != NULL; x++)
This loop will now set x to the values 0 through 6.
Now let's look at your inner loop:
for (g=0; *(*fruit)++; g++)
To reduce the stars circling our heads, let's replace *first by first[0]:
for (g=0; *(fruit[0])++; g++)
So *(fruit[0])++:
Obtains the value in the first element of the array (fruit[0]), which is a pointer (char *) to the first character of the string "Water";
Indirects via that pointer (*(fruit[0]) to obtain a single character, which is W;
Implicitly compares that character to the null byte - the test part of the for; and
Increments the pointer stored in the first element of the array
So after the first iteration of this loop the fruit array contains (assuming values as above):
0x100000e25
0x100000e2a
0x100000e31
The first element has now changed to point at the a in "Water". As you are reading the array to print it you are also changing it - probably not a good idea.
Also note that this loop always references the first element of the array, it never moves past it however many iterations of the outer loop occur - this loop is not stepping through the elements of fruit either - to do that you would need to reference x somewhere, which you do not in the for itself, but you do in the body:
putchar(*(*(fruit+x)+g))
which re-written using indexing is:
putchar(fruit[x][g])
which outputs the g'th character of the x'th element of fruit. This would make sense if the array fruit was not being modified, however as we've just determined the first element of fruit now references the a in "Water", x & g are both zero, so this outputs a and not W as you hoped.
Now consider the second iteration, the for loop examines the a and find it is not the null byte, so fruit[0] is incremented to reference the t in "Water" and g is incremented to 1. Now the putchar looks up the first element of fruit, which is referencing "ter..." having been incremented twice, g is 1 so the second character is selected, which is e, and that is output.
In each iteration you are incrementing the pointer in fruit[0] and incrementing g, so the sum increments by 2 each time and the putchar outputs the 2nd, 4th, 6th, 8th and 10th characters in memory... As the strings follow each other you get a, e and the null byte from "Water" and two a's from "banana".
As your program continues fruit[0] marches through memory but as the putchar uses x and so references the unchanged pointers in fruit[1] onwards the remaining strings, by luck, print out correctly. If you don't add the sentinel to the array the outer loop keeps marching through memory until a zero byte is found - so you may get garbage printed after blueberry as well.
So how do you fix this?
Well you should never have been altering fruit[0] in there first place, and you should be referencing x in your inner for to step through the array.
Keeping close to your original code a solution is to copy the pointer stored in fruit into a local variable and increment that to walk through the string:
char *fruit[] =
{ "Water",
"banana",
"pear",
"apple",
"coconut",
"grape",
"blueberry",
NULL
};
int x;
int g;
for(x=0; *(fruit+x) != NULL; x++)
{
char *p = *(fruit+x); // copy the x'th pointer from fruit and store it in p
for (g=0; *(p+g); g++) // step through the string incrementing p (not the x'th element of fruit)
{
putchar(*(p+g));
}
putchar('\n');
}
HTH
You forgot to NULL terminate your array:
char *fruit[] = {
"Water",
"banana",
"pear",
"apple",
"coconut",
"grape",
"blueberry",
NULL
};
You have been hit by undefined behavior.
Then use just puts like
for(x=0;fruit[x]!=NULL;x++)
puts(fruit[x]);
Please compile with all warnings and debug info (perhaps gcc -Wall -g) and use the debugger (gdb probably) - run your code step by step and print or display some relevant variables (like x or fruit)
The code is needlessly complicated. Is there a reason why you can't simply do like this?
#include <stdio.h>
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(*arr))
int main()
{
const char *fruit[] =
{
"Water",
"banana",
"pear",
"apple",
"coconut",
"grape",
"blueberry"
};
for(int i=0; i<ARRAY_SIZE(fruit); i++)
{
puts(fruit[i]);
}
return 0;
}

Logic challenge: sorting arrays alphabetically in C

I'm new to programming, currently learning C. I've been working at this problem for a week now, and I just can't seem to get the logic straight. This is straight from the book I'm using:
Build a program that uses an array of strings to store the following names:
"Florida"
"Oregon"
"Califoria"
"Georgia"
Using the preceding array of strings, write your own sort() function to display each state's name in alphabetical order using the strcmp() function.
So, let's say I have:
char *statesArray[4] = {"Florida", "Oregon", "California", "Georgia"};
Should I do nested for loops, like strcmp(string[x], string[y])...? I've hacked and hacked away. I just can't wrap my head around the algorithm required to solve this even somewhat efficiently. Help MUCH appreciated!!!
imagine you had to sort the array - think of each state written on a card. HOw would you sort it into order. There are many ways of doing it. Each one is called an algorithm
One way is to find the first state by looking at every card and keeping track in your head of the lowest one you have seen. After looking at each card you will have the lowest one. Put that in a new pile. NOw repeat - trying to find the lowest of the ones you have left.
repeat till no cards left in original pile
This is a well known simple but slow algorithm. Its the one i would do first
there are other ones too
Yes, you can sort by using nested for loops. After you understand how strcmp() works it should be fairly straight forward:
strcmp(char *string1, char *string2)
if Return value is < 0 then it indicates string1 is less than string2
if Return value is > 0 then it indicates string2 is less than string1
if Return value is = 0 then it indicates string1 is equal to string2
You can then choose any of the sorting methods once from this point
This site has a ton of great graphical examples of various sorts being performed and includes the pseudo code for the given algorithms.
Do you need "any" sorting algorithm, or an "efficient" sorting algorithm?
For simplicity, I can show you how to implement an easy, but not efficient, sorting algorithm.
It's the double for method!!
Then, with the same ideas, you can modify it to any other efficient algorithm (like shell, or quicksort).
For numbers, you could put arrays ir order, as follows (as you probably know):
int intcmp(int a, int b) {
return (a < b)? -1: ((a > b)? +1: 0);
}
int main(void) {
int a[5] = {3, 4, 22, -13, 9};
for (int i = 0; i < 5; i++) {
for (int j = i+1; j < 5; j++)
if (intcmp(a[i], a[j]) > 0) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
printf("%d ", a[i]);
}
}
The only thing that has changed now is that you have strings intead integers.
So, you have to consider an array of strings:
char *a[] = {"Florida", "Oregon", "Califoria", "Georgia"};
Then, you have to change the type of temp to char*,
and finally you put the function strcmp() instead of intcmp().
The function strcmp(s1, s2) (from < string.h >)
returns a number < 0 if s1 is a string "less than" s2, == 0 if s1 is
"equal to" s2, and > 1 else.
The program looks like this:
#include <stdio.h>
#include <string.h>
int main(void) {
char *a[] = {"Florida", "Oregon", "Califoria", "Georgia"};
for (int i = 0; i < 4; i++) {
for (int j = i+1; j < 4; j++)
if (strcmp(a[i], a[j]) > 0) {
char* temp = a[i];
a[i] = a[j];
a[j] = temp;
}
printf("%s ", a[i]);
}
getchar();
return 0;
}
Note that for the printf() sentence, we have changed "%d " by "%s ", in order to properly show strings.
Final comment: When you program a better algorithm, like quick-sort, it is enough that you change the comparisson function, because the algorithm it is the same, in despite of the type of data you are comparing.
Remark: I have used a "tricky" method. As you can see, I have defined the variable a as a pointer to string. The initializer has taken a constant array of strings and then initialized the variable a with it. The variable a now can be safely treated and indexed as an array of exactly 4 pointer-to-strings.
That is the reason why the "swap" works fine in the double-for algorithm: The memory addresses are swapped instead the entire strings.
Steps you likely should take:
Populate array with state names
Create method to swap two states in place in the array
At this point you have all the tools necessary to use strcmp to implement any sorting algorithm you choose
Most sorting methods rely on two things.
Being able to rearrange a list (i.e. swap)
Being able to compare items in list to see if they should be swapped
I would work on getting those two things working correctly and the rest should just be learning a particular sorting algorithm
Beware of a little headaching problem: Strings are sorted by ascii numeric representations, so if you sort alphabetically like this, any capital letter will come before a lowercase letter e.g. "alpha", "beta", "gamma", "Theta" will be sorted as:
Theta, alpha, beta, gamma
When it comes to the sample array you have listed here the simple algorithm mentioned earlier might actually be the most efficient. The algorithm I'm referring to is the one where you start with the first element and then compare it to the others and substitute with the smallest you find and then going to the next element to do the same only dont compare it to the already sorted elements.
While this algorithm has an execution time of O(n^2). Where n is the number of elements in the array. It will usually be faster than something like quick sort (execution time O(n*log(n)) for smaller arrays. The reason being that quick sort has more overhead. For larger arrays quick sort will serve you better than the other method, which if memory serves me right is called substitution sort although I see it mentioned as "double for" in a different answer.

Resources