C language: args in functions inside Main (). Unclear what they are - c

I have been struggling to understand some pieces of this code. It asks to enter some strings, will count the vowels and display the result. It is some definitions that I don't understand, the mechanics I do.
In the definitions inside main(). I dont understand what for an argument this '(cad)' is in the entrada function. One line above it is defined an array of 3 pointers to char, namely char *cad[N] if I correctly believe. I would say my problem is everything in the Main function, how the arguments make sense inside the parentheses for the functions. After that I understand alright.
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include<ctype.h>
# define N 3
// Function Prototypes
void salida(char *[], int*);
void entrada(char *[]);
int vocales(char *);
int main ()
{
char *cad[N]; // declaring an array of 3 pointers to char
int j, voc[N]; // declaring ints and an array of ints
entrada (cad);// Function to read in strings of characters.
// count how many vowels per line
for (j = 0; j<N; j++)
voc[j] = vocales(cad[j]); // it gets the string and sends it to function vocales to count how many vowels. Returns number to array voc[j]
salida (cad, voc);
}
// Function to read N characters of a string
void entrada(char *cd[] ){
char B[121]; // it just creates an array long enough to hold a line of text
int j, tam;
printf("Enter %d strings of text\n", N );
for (j= 0; j < N; j++){
printf ("Cadena[%d]:", j + 1);
gets(B);
tam = (strlen(B)+1)* sizeof(char); // it counts the number of characters in one line
cd[j] = (char *)malloc (tam); // it allocates dynamically for every line and array index enough space to accommodate that line
strcpy(cd[j], B); // copies the line entered into the array having above previously reserved enough space for that array index
} // so here it has created 3 inputs for each array index and has filled them with the string. Next will be to get the vowels out of it
}
// Now counting the number of vowels in a line
int vocales(char *c){
int k, j;
for(j= k= 0; j<strlen(c); j++)
switch (tolower (*(c+j)))
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
k++;
break;
}
return k;
}
// function to print the number of vowels that each line has
void salida(char *cd[], int *v)
{
int j;
puts ("\n\t Displaying strings together with the number of characters");
for (j = 0; j < N; j++)
{
printf("Cadena[%d]: %s has %d vowels \n", j+1, cd[j], v[j]);
}
}

cad is an array of pointers. It only has space for N pointers, not the actual string data. The entrada function reads N strings of text. For each of these it allocates some space with malloc and copies the string there. entrada sets the corresponding pointer in cad (which it sees as cd) to point to the allocated buffer.
When you pass an array as an argument, you are not passing a copy. Instead, the address of the first element is passed to the function. This is how entrada can modify the pointers in cad.

Related

Dynamic arrays and unexpected output

I have written this script, and the aim of it is to get in input a phrase and to print just the first word (the one before the first space). I cannot understand why, when I execute it, I get a bunch of numbers in the output.
#include <stdio.h>
#include <stdlib.h>
#define MAX 30
/*
Prende in input una frase e stampa la prima parola
*/
char *fw();
int main () {
int j,i;
char parola[MAX], *p;
printf ("Inserisci una stringa: ");
fgets(parola, MAX, stdin);
p = fw(&parola, &i);
for (j=0; j < i; j++){
printf("%d", p[j]);
}
return 0;
}
char *fw(char *parola, int *puntatoreI) {
int i;
char *p;
for (i=0; parola[i]!=' '; i++)
;
p = (char *)malloc((i+1)*sizeof(char));
for (i=0; parola[i]!=' '; i++){
p[i] = parola[i];
}
p[i+1] = '\0';
puntatoreI = &i;
return p;
}
puntatoreI = &i;
Is assigning a pointer puntatoreI to point to variable i. You don't want to do that. You want to modify variable i inside main, that is where the pointer puntatoreI points to. You want:
*puntatoreI = i;
You are allocating (i+1) characters for p. Yet you are assigning to p[i+1] = '\0'; is accessing 1-byte out of bounds. Just p[i] = '\0';. i is the last index in an array of i+1 elements.
Using empty braces in function declaration char *fw(); is very old. To make sure your code is ok, just repeat the function declaration from the definition char *fw(char *parola, int *puntatoreI);.
The type of &parola is char (*)[30] - it's a pointer to an array of 30 characters. Yet, the fw function takes char * - a pointer to char. Just pass parola as in p = fw(parola, &i);.
And finally, to your question:
why when I execute it I get a bunch of numbers in output.
You get a "bunch of numbers" on the output, because you print them with printf("%d",p[j]);. %d is a printf format specifier used to print numbers in base 10. To print characters as they are, use %c format specifier. But because p should point to a zero-terminated array of characters (to a string), you could do just printf("%s", p); instead of the whole loop.

How to count the number of same character in C?

I'm writing a code a that prompts the user to enter a string
&
create a function that is a type void that prints out the character that was used the most
(As in where it appeared more than any other ones)
&
also shows the number of how many times it was in that string.
Therefore here is what I have so far...
#include <stdio.h>
#include <string.h>
/* frequent character in the string along with the length of the string (use strlen from string.h – this will require you to #include <string.h> at the top of your program).*/
/* Use array syntax (e.g. array[5]) to access the elements of your array.
* Write a program that prompts a user to input a string,
* accepts the string as input, and outputs the most
* You should implement a function called mostfrequent.
* The function prototype for mostfrequent is: void mostfrequent(int *counts, char *most_freq, int *qty_most_freq, int num_counts);
* Hint: Consider the integer value of the ASCII characters and how the offsets can be translated to ints.
* Assume the user inputs only the characters a through z (all lowercase, no spaces).
*/
void mostfrequent(int *counts, char *most_freq, int *qty_most_freq, int num_counts_)
{
int array[255] = {0}; // initialize all elements to 0
int i, index;
for(i = 0; most_freq[i] != 0; i++)
{
++array[most_freq[i]];
}
// Find the letter that was used the most
qty_most_freq = array[0];
for(i = 0; most_freq[i] != 0; i++)
{
if(array[most_freq[i]] > qty_most_freq)
{
qty_most_freq = array[most_freq[i]];
counts = i;
}
num_counts_++;
}
printf("The most frequent character was: '%c' with %d occurances \n", most_freq[index], counts);
printf("%d characters were used \n", num_counts_);
}
int main()
{
char array[5];
printf("Enter a string ");
scanf("%s", array);
int count = sizeof(array);
mostfrequent(count , array, 0, 0);
return 0;
}
I'm getting the wrong output too.
output:
Enter a string hello
The most frequent character was: 'h' with 2 occurances
5 characters were used
should be
The most frequent character was: 'l' with 2 occurances
5 characters were used
let's do it short (others will correct me if I write something wrong ^_^ )
you declare a int like this:
int var;
use it like this :
var = 3;
you declare a pointer like this :
int* pvar;
and use the pointed value like this:
*pvar = 3;
if you declared a variable and need to pass a pointer to it as function parameters, use the & operator like this :
functionA(&var);
or simply save its address in a pointer var :
pvar = &var;
that's the basics. I hope it will help...
The function prototype you are supposed to use seems to include at least one superfluous parameter. (you have the total character count available in main()). In order to find the most frequently appearing character (at least the 1st of the characters that occur that number of times), all you need to provide your function is:
the character string to be evaluated;
an array sized so that each element represents on in the range of values you want to find the most frequent (for ASCII characters 128 is fine, for all in the range of unsigned char, 256 will do); and finally
a pointer to return the index in your frequency array that holds the index to the most frequently used character (or the 1st character of a set if more than one are used that same number of times).
In your function, your goal is to loop over each character in your string. In the frequency array (that you have initialized all zero), you will map each character to an element in the frequency array and increment the value at that element each time the character is encountered. For example for "hello", you would increment:
frequency['h']++;
frequency['e']++;
frequency['l']++;
frequency['l']++;
frequency['o']++;
Above you can see when you are done, the element frequency['l']; will hold the value of 2. So when you are done you just loop over all elements in frequency and find the index for the element that holds the largest value.
if (frequency[i] > frequency[most])
most = i;
(which is also why you will get the first of all characters that appear that number of times. If you change to >= you will get the last of that set of characters. Also, in your character count you ignore the 6th character, the '\n', which is fine for single-line input, but for multi-line input you need to consider how you want to handle that)
In your case, putting it altogether, you could do something similar to:
#include <stdio.h>
#include <ctype.h>
enum { CHARS = 255, MAXC = 1024 }; /* constants used below */
void mostfrequent (const char *s, int *c, int *most)
{
for (; *s; s++) /* loop over each char, fill c, set most index */
if (isalpha (*s) && ++c[(int)*s] > c[*most])
*most = *s;
}
int main (void) {
char buf[MAXC];
int c[CHARS] = {0}, n = 0, ndx;
/* read all chars into buf up to MAXC-1 chars */
while (n < MAXC-1 && (buf[n] = getchar()) != '\n' && buf[n] != EOF)
n++;
buf[n] = 0; /* nul-terminate buf */
mostfrequent (buf, c, &ndx); /* fill c with most freq, set index */
printf ("most frequent char: %c (occurs %d times, %d chars used)\n",
ndx, c[ndx], n);
}
(note: by using isalpha() in the comparison it will handle both upper/lower case characters, you can adjust as desired by simply checking upper/lower case or just converting all characters to one case or another)
Example Use/Output
$ echo "hello" | ./bin/mostfreqchar3
most frequent char: l (occurs 2 times, 5 chars used)
(note: if you use "heello", you will still receive "most frequent char: e (occurs 2 times, 6 chars used)" due to 'e' being the first of two character that are seen the same number of times)
There are many ways to handle frequency problems, but in essence they all work in the same manner. With ASCII characters, you can capture both the most frequent character and the number of times it occurs in a single array of int and an int holding the index to where the max occurs. (you don't really need the index either -- it just save looping to find it each time it is needed).
For more complex types, you will generally use a simple struct to hold the count and the object. For example if you were looking for the most frequent word, you would generally use a struct such as:
struct wfreq {
char *word;
int count;
}
Then you simply use an array of struct wfreq in the same way you are using your array of int here. Look things over and let me know if you have further questions.
Here is what I came up with. I messed up with the pointers.
void mostfrequent(int *counts, char *most_freq, int *qty_most_freq, int num_counts_)
{
*qty_most_freq = counts[0];
*most_freq = 'a';
int i;
for(i = 0; i < num_counts_; i++)
{
if(counts[i] > *qty_most_freq)
{
*qty_most_freq = counts[i];
*most_freq = 'a' + i;
}
}
}
/* char string[80]
* read in string
* int counts[26]; // histogram
* zero counts (zero the array)
* look at each character in string and update the histogram
*/
int main()
{
int i;
int num_chars = 26;
int counts[num_chars];
char string[100];
/*zero out the counts array */
for(i = 0; i < num_chars; i++)
{
counts[i] = 0;
}
printf("Enter a string ");
scanf("%s", string);
for(i = 0; i < strlen(string); i++)
{
counts[(string[i] - 'a')]++;
}
int qty_most_freq;
char most_freq;
mostfrequent(counts , &most_freq, &qty_most_freq, num_chars);
printf("The most frequent character was: '%c' with %d occurances \n", most_freq, qty_most_freq);
printf("%d characters were used \n", strlen(string));
return 0;
}

C - Creating an array of character arrays

I am trying to make an array of character Arrays. The program will read in sentences and store the sentences in a character array, and then that character array will be stored in another array. After reading numerous websites and Stack Over Flow pages I think it can be done like this. The program breaks when trying to store my character array into another array, so i'm not sure how to correct my code.
#include <stdio.h>
#include <math.h>
#include <time.h>
int main(int ac, char *av[])
{
int size; //number of sentences
char strings[100];// character array to hold the sentences
char temp;
printf("Number of Strings: ");
scanf_s("%d", &size); // read in the number of sentences to type
char **c = malloc(size); //array of character arrays
int i = 0;
int j = 0;
while (i < size) //loop for number of sentences
{
printf("Enter string %i ",(i+1));
scanf_s("%c", &temp); // temp statement to clear buffer
fgets(strings, 100, stdin);
// **** this next line breaks the program
c[i][j] = strings; // store sentence into array of character arrays
j++;
i++;
}
printf("The first character in element 0 is: %d\n", c[0][0]);
system("PAUSE");
return 0;
}
Al you need to do is allocate the memory for the string just read and copy the string:
c[i][j] = strings; // replace this with:
c[i]= malloc(strlen(strings)+1);
strcpy(c[i],strings);
Sadly char **c is not array of characters arrays. But this will properly allocate a 2d array dynamically if you follow
char (*c)[SIZE];
And then doing this
c = malloc(sizeof(char[LEN][SIZE]));
Then you do what you are trying to do.
for(size_t i = 0; i < LEN; i++){
if(fgets(c[i],SIZE,stdin)){
...
}
}
Or you can do it like this
char **c = malloc(LEN);
..
for(size_t i = 0; i < LEN; i++){
c[i] = malloc(SIZE);
...
}
But again c is nothing but jagged array of characters.
Check the return value of malloc and free the dynamically allocated memory when you are done working with it.
Listen dude,
Do you want to store the words in the character array and then store this in another array.
It is what you want ?
If yes then you can do the following.
Use stdlib by using # include <stdlib.h> .
This lets you use string functions directly.
Now read every word as a string and make array of strings.
So now if you number of strings is n, define an array for that as string my_array[n] and scan each word using scanf("%s",&my_array [i]).
In this way you will get an array of strings.

function to get words and put them in array

I need to write a C function that gets from the user the number of the words that he wants to enter, then the function has to scan the word from the user and but them in the array.
For example:
Program:
number of words:
User:
3
hi
my
name
(between every word there is enter) then the function has to put these words in
string array (the size of the array must be defined by malloc and the max size of the string is 100 (could be less)).
int main()
{
int n;
printf("Please enter the number of words: \n");
if (scanf("%d",&n)!=1)
return 0;
char *name;
name = malloc((sizeof(char)*100*n));
int c;
int i;
int m;
for (i = 0; i < n && ((c=getchar()) != EOF );i++)
{
name[i] = c;
}
finds_themin(&name, m); //I know this work
return 0;
}
You need to setup a pointer to pointer.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
char **s;
int n;
char buffer[64];
fgets(buffer,64,stdin);
n=strtol(buffer,NULL,10);// I avoid using scanf
s=(char **)malloc(sizeof(char*)*n);// you need to declare a pointer to pointer
/*
'PtP s' would look like this:
s[0]=a char pointer so this will point to an individual string
s[1]=a char pointer so this will point to an individual string
s[2]=a char pointer so this will point to an individual string
....
so you need to allocate memory for each pointer within s.
*/
int i;
for(i=0;i<n;i++){
s[i]=(char*)malloc(sizeof(char)*100);// length of each string is 100 in this case
}
for(i=0;i<n;i++){
fgets(s[i],100,stdin);
if(strlen(s[i])>=1){// to avoid undefined behavior in case of null byte input
if(s[i][strlen(s[i])-1]=='\n'){ // fgets also puts that newline character if the string is smaller than from max length,
s[i][strlen(s[i])-1]='\0'; // just removing that newline feed from each string
}
else{
while((getchar())!='\n'); //if the string in the command line was more than 100 chars you need to remove the remaining chars for next fgets
}
}
}
for(i=0;i<n;i++){
printf("\n%s",s[i]);
}
for(i=0;i<n;i++){
free(s[i]); //avoiding leaks
}
free(s);
}
As you need to store an array of strings you need an array of char* or char** to point each string (char array).
char **name;
name = malloc(n); // to store n strings.
Then in the loop use fgets to read the input as a line. Also, you need to allocate the memory for each new char array.
fflush(stdin);
for (i = 0; i < n; i++) {
name[i] = malloc(100); // allocating memory for string.
fgets (name[i], 100, stdin); // 100 is the max len
}
You can then simply iterate over the char** array, the ith index will point to the ith string.
for (i = 0; i < n; i++) {
// printf("%s", name[i]);
}

strings of characters in C

I am trying to solve a C problem where I have to sort n strings of characters using pointers.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sort (char *s, int n)
{
int i,j; char aux[]="";
for (i=1;i<=n-1;i++)
{
for (j=i+1;j<=n;j++) //if s[i]> s[j] switch
{
if (strcmp(*(s+i),*(s+j))==1)
{
strcpy(aux,*(s+i);
strcpy(*(s+i),*(s+j));
strcpy(*(s+j),*(s+i));
}
}
}
}
void show(char *s, int n)
{
int i;
for (i=1;i<=n;i++)
{
printf("%s",*(s+i));
}
}
int main()
{
int i,n; char *s;
printf("give the number of strings:\n");
scanf("%d",&n);
s=(char*)calloc(n,sizeof(char));
for (i=1;i<=n;i++)
{
printf("s[%d]= ",i);
scanf("%s",s+i);
}
sort(s,n);
show(s,n);
return 0;
}
The warnings that I get are when I use strcmp to compare and when I use strcpy to switch *(s+i) and *(s+j) values.
"passing argument 2 of strcmp makes pointer from integer without a cast"
The warnings that I get are when I use strcmp to compare and when I use strcpy to switch *(s+i) and *(s+j) values.
"passing argument 2 of strcmp makes pointer from integer without a cast"
You are wrong argument to strcmp and strcpy. Signature of strcmp and strcpy are
int strcmp(char *string1, char *string2);
char *strcpy(char *dest, const char *src)
But you are passing it the arguments of char type. Removefrom(s+i)and*(s+j)`. It should be
if (strcmp((s+i), (s+j))==1)
{
strcpy(aux, (s+i));
strcpy((s+i), (s+j));
strcpy((s+j), (s+i));
}
Another problem is you have not allocated memory for the pointer s. For characters, you can declare it as
s = malloc ( (n + 1)*sizeof(char) );
or simply
s = malloc ( n + 1 ); // +1 is for string terminator '\0'
You seem to have mis-understood the return value of strcmp(); it's an integer that will be 0 (zero) if and only if the two string arguments are equal. You're testing for 1, which it will only be rarely; it has no specific meaning.
Consider just using qsort().
You're allocating space for n strings of 1 byte each. The easiest approach is to assume each string will be less than some set length, like 40 bytes. Then you would allocate the memory like this:
s=(char*)calloc(n*(40),sizeof(char));
Then your scanf needs to be modified:
scanf("%s",s+(i*40));
Now, string 1 will be at *s, string 2 will be at *(s+40), etc. Keep in mind that a string ends with a null character (0x00), so the string can only contain 39 chars. Any unused data will also be 0x00.
Do the same s+(i*40) for the sorting algorithm, compare to >0, not ==1, and strcmp, strcpy expect pointers. Then you should be good.
In your code there are a lots of mistakes: in variable declarations, memory allocation and pointer usage.
First remember that you should always reserve enough space to store your string values, and be aware to don't try to store a string with a length greater then the reserved space.
Also you should be very careful managing pointers (s+1 doesn't point to the first string but to the second one, s+n points out of the allocated memory)
So, as mentioned in other answers you should decide the maximum size of your strings an then allocate for them the right amount of memory.
Then I suggest you to use a pointer to strings, i.e. a char** to access your strings and manage the sort, in this way the code is more readable and the sort is faster (you don't need to copy strings, but only to switch pointers)
So your main function should be:
int main()
{
int i, n;
// Declare the pointer to the memory where allocate the space for the strings
char* a; // points to a char ( == is a string)
// Declare the pointer to the memory where store the pointer to the strings
char** s; // points to a char* ( == is a pointer to a string)
printf("give the number of strings:\n");
scanf("%d", &n);
// Allocate the memory for n strings of maximum 40 chars + one more for the null terminator
a=(char*)calloc(n*41, sizeof(char));
// Allocate memory for n pointers to a string
s=(char**)calloc(n, sizeof(char*));
// Notice the 0-based loop
for (i=0; i<n; i++)
{
s[i] = a + i*41; // set the i-th element of s to point the i*41-th char in a
printf("s[%d]= ", i);
scanf("%40s", s[i]); // read at least 40 characters in s[i],
// otherwise it will overflow the allocated size
// and could generate errors or dangerous side effects
}
sort(s,n);
show(s,n);
// Remember always to free the allocated memory
free(s);
free(a);
return 0;
}
the sort function sorts an array of pointers, without copying strings:
void sort (char** s, int n)
{
int i, j;
char* aux;
// Notice the 0-based loop
for (i=0; i<n; i++)
{
for (j=i+1; j<n; j++) //if s[i]> s[j] switch
{
if (strcmp(s[i], s[j])>0)
{
// You don't need to copy strings because you simply copy pointers
aux = s[i];
s[i] = s[j];
s[j] = aux;
}
}
}
}
finally the correct show function:
void show(char** s, int n)
{
int i;
// Notice the 0-based loop
for (i=0; i<n; i++)
{
printf("%s", s[i]);
}
}
I can't test the code but it should works
Added other options
1) If you have troubles with dynamic memory allocation you can use instead static allocation, your main function then will be:
int main()
{
int i, n;
// Declare an array of fixed lenght strings
char s[100][41]; // You manage max 100 strings
printf("give the number of strings:\n");
scanf("%d", &n);
// Ensure that n is less or equal maximum
if (n>100)
{
printf("you'll be asked for a maximum of 100 strings\n");
n=100;
}
// Notice the 0-based loop
for (i=0; i<n; i++)
{
printf("s[%d]= ", i);
scanf("%40s", s[i]); // read at least 40 characters in s[i],
// otherwise it will overflow the allocated size
// and could generate errors or dangerous side effects
}
sort(s,n);
show(s,n);
// You don't need to free any memory
return 0;
}
all other functions remain unchanged.
2) Whereas, if you want the maximum freedom in the memory you need you can choose a two allocate memory separately for each string only for the needed size, in this case your main funcion will be:
int main()
{
int i, n;
char buffer[1000]; // You need a buffer to read input, before known its actual size
// Declare the pointer to the memory where store the pointer to the strings
char** s; // points to a char* ( == is a pointer to a string)
printf("give the number of strings:\n");
scanf("%d", &n);
// Allocate memory for n pointers to a string
s=(char**)calloc(n, sizeof(char*));
// Notice the 0-based loop
for (i=0; i<n; i++)
{
printf("s[%d]= ", i);
scanf("%999s", buffer); // read at least 999 characters in buffer,
// otherwise it will overflow the allocated size
// and could generate errors or dangerous side effects
// Allocate only the memory you need to store the actual size of the string
s[i] = (char*)calloc(strlen(buffer)+1, sizeof(char)); // Remember always 1 more char for the null terminator
// Copy the buffer into the newly allocated string
strcpy(s[i], buffer);
}
sort(s,n);
show(s,n);
// Remember always to free the allocated memory
// Now you have first to free the memory allocated for each string
for (i=0; i<n; i++)
{
free(s[i]);
}
// Then you can free the memory allocated for the array of strings
free(s);
return 0;
}
all other functions remains unchanged too.

Resources