How does the pointer in C work in this algorithm? - c

I have a program to calculate the highest value of consonants in a string as followed:
int solve(const char* strin) {
char *vowels = "aeiou";
int solution = 0;
int current = 0;
char *c;
while(c = *strin++) {
current = strchr(vowels, c) ? 0 : current + c - 96;
if(current > solution) solution = current;
}
return solution;
}
I got quite confused with the command char *vowels = "aeiou"; because, as I've learned at university, the pointer only refers to the first element in an array unless there exists an increment or decrement. Is it valid to write like this? And why?

When you write
char* vowels = "aeiou";
the pointer vowels points to the first element of the "array" i.e. 'a', what you do with that pointer is up to you, if you e.g. want access the third element that vowels points to then *(vowels + 2) will give you that - the address of the same is vowels + 2
you can also declare vowels like this
char vowels[] = "aeiou"; here vowels again tells where the array starts
the prototype of strchr looks like this
char *strchr( const char *str, int ch );
When you pass in vowels you tell the function to start looking where vowels starts for the 'ch'. strchr looks until it finds the end of the string which is a \0, if it finds it returns a pointer to that location i.e. vowels + 0, +1 ,...

Related

Reversing a string in C without the output being null

I am trying to reverse a string (character array) using the following code, but when I attempt to print the string, the value of null. This is a homework assignment, but I am trying to learn so any help would be appreciated.
void input_reverse_string(const char* inputStr, char* reverseStr)
{
int i = 0;
int length = 0;
for (; *(inputStr++) != '\0'; i++)
{
length++;
}
while (*inputStr)
{
*reverseStr = *inputStr;
inputStr++;
reverseStr++;
}
const char* chr_ptr = &inputStr[length - 1];
printf("I see a %s\n", *chr_ptr);
*reverseStr = '\0';
printf("%d", length);
/* return reverseStr; */
}
Several things are out of order:
That's a strange way of computing the length of a string. You are using an index variable that you don't need, and incrementing 3 things at the same time, it's unneeded to say the least.
After calculating the length, and incrementing the inputStr pointer up to its end, you don't reset the pointer, so it still points to the end of the string (actually, one after the end!).
Inside the while you are advancing both pointers (inputStr and reverseStr) in the same direction, which can't possibly be right if you want to reverse the string.
The correct way to do this would be:
Compute the length of the string. Either use strlen() or do it by hand, but you really only need to increment one variable to do this. You can avoid incrementing inputStr, just use a temporary pointer.
Start from inputStr + length and walk backwards. Either use a pointer and do -- or just index the string).
Here's a working example:
void reverse_string(const char* inputStr, char* reverseStr) {
unsigned len = 0;
int i;
while (inputStr[len])
len++;
for (i = len - 1; i >= 0; i--) {
reverseStr[len - i - 1] = inputStr[i];
}
reverseStr[len] = '\0';
}
int main(void) {
char a[6] = "hello";
char b[6];
reverse_string(a, b);
puts(b);
return 0;
}
Output:
olleh

Insert char into char array C (string)

I got the char array "anana" and I am trying to get a "B" into the beginning in the char array so it spells "Banana" but I cannot wrap my head around how to construct a simple while loop to insert the B and then move every letter one step to the right
Assuming:
char array[7] = "anana";
Then:
memmove(array+1, array, 6);
array[0] = 'B';
The memmove function is specifically for cases where the data movement involves an overlap.
You can use a more traditional approach using...
#include <stdio.h>
int main()
{
char s[] = "ananas";
char b[7] = "B";
for(int i = 0; i < 7; ) {
char temp = s[i++];
b[i] = temp;
}
printf("%s", b);
return 0;
}
Please follow these steps:
Create a new array of size 7 (Banana + terminator). You may do this dynamically by finding the size of the input string using strlen().
Place your desired character say 'B' at newArray[0].
Loop over i=1 -> 7
Copy values as newArray[i] = oldArray[i-1];

Can anyone explain to me this piece of code? I am new to C

I am trying to learn C, so I went to try out some of the coderbyte challenges in C, one of which is to reverse a string. After gettung multiple compilation errors due to syntax I tried looking for examples and encountered this one on http://www.programmingsimplified.com/c-program-reverse-string
#include<stdio.h>
int string_length(char*);
void reverse(char*);
main()
{
char string[100];
printf("Enter a string\n");
gets(string);
reverse(string);
printf("Reverse of entered string is \"%s\".\n", string);
return 0;
}
void reverse(char *string)
{
int length, c;
char *begin, *end, temp;
length = string_length(string);
begin = string;
end = string;
for (c = 0; c < length - 1; c++)
end++;
for (c = 0; c < length/2; c++)
{
temp = *end;
*end = *begin;
*begin = temp;
begin++;
end--;
}
}
int string_length(char *pointer)
{
int c = 0;
while( *(pointer + c) != '\0' )//I DON'T UNDERSTAND THIS PART!!!!!
c++;
return c;
}
c is not even a char, so why would you add it? Or is pointer some sort of index considering the context of the while loop?
The + operator here does not mean string concatenation; it means pointer arithmetic. pointer is a pointer to a char, and c is an int, so pointer + c results in a pointer to a char that is c chars further forward in memory. For example, if you have an array {'j', 'k', 'l', 'm'} and pointer pointed at the 'j', and c was 2, then pointer + c would point at the 'l'. If you advance a pointer like this then deference it, that acts the same as the array indexing syntax: pointer[c]. The loop is therefore equivalent to:
while( pointer[c] != '\0' )
c++;
The effect of adding a pointer to an integer (or vice-versa) scales according to the size of what the pointer is (supposedly) pointing to, so you don't need to account for different sizes of objects. foo + 5, if foo is a pointer, will go 5 objects further forward in memory, whatever size object foo points to (assuming that foo is pointing at the type it is declared to point to).
Here you can talk about pointer arithmetic.
There is an important concept :
Addition a integer to a pointer will move the pointer forward. The number that you are adding will be multiplied by the size of type that the pointer is pointing to.
Example :
An int is coded on 4 bytes, so when we increment the pointer by 1, we have to multiply by 4 to obtain what really happen in regular arithmetic.
int a[3] = {1, 3, 6};
printf("%d\n", *(a + 1)); // print 3, look 4 bytes ahead
printf("%d \n", *(a + 2)); //print 6, look 8 bytes ahead
In your case :
A char is coded on 1 byte so
*(pointer + c) with c == 3
will evaluate to a memory address of 3 bytes (3 chars) ahead.
So the code :
while( *(pointer + c) != '\0' )
c++;
will evaluate the value of your pointer at a specific memory address. If the character is equal to the null-character, we have reached the end of the string.
Remember that *(pointer + c) is equivalent to pointer[c].
c is being used as an index.
/* reverse: Reverses the string pointed to by `string` */
void reverse(char *string)
{
int length, c;
char *begin, *end, temp;
/* compute length of string, initialize pointers */
length = string_length(string);
begin = string; /* points to the beginning of string */
end = string; /* will later point to the end of string */
/* make end point to the end */
for (c = 0; c < length - 1; c++)
end++;
/* walk through half of the string */
for (c = 0; c < length/2; c++)
{
/* swap the begin and end pointers */
temp = *end;
*end = *begin;
*begin = temp;
/* advance pointers */
begin++;
end--;
}
}
/* computes length of pointer */
int string_length(char *pointer)
{
int c = 0;
/* while we walk `pointer` and we don't see the null terminator */
while( *(pointer + c) != '\0' )//I DON'T UNDERSTAND THIS PART!!!!!
c++; /* advance position, c */
/* return the length */
return c;
}
The string_length function can be rewritten as
size_t strlen(const char *str)
{
size_t i;
for (i = 0; *str; ++i)
;
return i;
}
From what I understand if the string is : abcd
the result would be : dcba
if the input is : HELLO-WORLD
the output would be : DLROW-OLLEH

Find Every Position of a Given Char Within an Array

I made a small function that fills an allocated block of memory containing every position of a given char within a given string and returns a pointer to the memory block.
The only problem with this function is that there is no way to check the size of the memory block; so I also made a function that counts the occurrence of a given char within a string.
Here is an example of use:
/*count occurences of char within a given string*/
size_t strchroc(const char *str, const char ch)
{
int c = 0;
while(*str) if(*(str++) == ch) c++;
return c;
}
/*build array of positions of given char occurences within a given string*/
int *chrpos(const char *str, const char ch)
{
int *array, *tmp, c = 0, i = 0;
if(!(array = malloc(strlen(str) * sizeof(int)))) return 0x00;
while(str[c])
{
if(str[c] == ch) array[i++] = c;
c++;
}
if(!(tmp = realloc(array, i * sizeof(int)))) return 0x00;
array = tmp;
return array;
}
int main(void)
{
char *str = "foobar foobar"; //'o' occurs at str[1], str[2], str[8], and str[9]
int *array, b = 0, d;
if(!(array = chrpos(str, 'o'))) exit(1); //array[0] = 1, array[1] = 2, array[2] = 8, array[3] = 9
/*
* This is okay since I know that 'o'
* only occures 4 times in str. There
* may however be cases where I do not
* know how many times a given char
* occurs so I figure that out before
* utilizing the contents of array.
* I do this with my function strchroc.
* Below is a sample of how I would
* utilize the data contained within
* array. This simply prints out str
* and on a new line prints the given
* char's location within the str
* array
*/
puts(str);
while(b < (int) strchroc(str, 'o')) //loop once for each 'o'
{
for(d = 0; d < (b == 0 ? array[b] : array[b] - array[b - 1] - 1); d++) putc((int) ' ', stdout);
printf("%d", array[b]);
b++;
}
}
Output:
foobar foobar
12 89
My only concern is that if one of these two functions fail, there is no way for the data to be used correctly. I was thinking about making the number of occurrences of char within the string an argument for chrpos but even then I would still have to call both functions.
I was wondering if anybody had any suggestions for a way to do this so that I only need one function to build the array.
The only way I can think of is by storing the number of char occurrences into array[0] and having array[1] through array[char_occurences] holding the positions of char.
If anybody has a better idea I would greatly appreciate it.
As stated in my comment the first thing is to save up the data anyway, in case you can't shrink the allocated memory :
if (!(tmp = realloc(array, i * sizeof(int))))
return array;
return (tmp); //array = tmp; is useless
If you want to protect a bit more your strchroc function add a if (!str) return 0; at the beginning.
You can change your function so that it also "returns" the number of occurrences found. While we cannot actually return multiple values from a function in C, we can pass a pointer as a parameter and have the function write down a value using that pointer:
int *chrpos(const char *str, char ch, int *found) {
/*
...
*/
*found = i;
return array;
}
Note that you don't need the const modifier for ch.

C101--string vs. char:

AFunc changes what was sent to it, and the printf() outputs the changes:
void AFunc ( char *myStr, int *myNum )
{
*myStr = 's';
*myNum = 9;
}
int main ( int argc, char *argv[] )
{
char someString = 'm';
int n = 6;
AFunc(&someString, &n);
printf("%c" "%d", someString, n);
}
But what if the string was more than one char? How would the code look differently? Thanks for any help.
If it were a "string" instead of a char, you would do something like this:
#include <stdio.h>
void AFunc (char *myStr, int *myNum) {
myStr[0] = 'p'; // or replace the lot with strcpy(myStr, "pax");
myStr[1] = 'a';
myStr[2] = 'x';
myStr[3] = '\0';
*myNum = 9;
}
int main (void) {
char someString[4];
int n = 6;
AFunc(someString, &n);
printf("%s %d", someString, n);
return 0;
}
which outputs:
pax 9
A "string" in C is really an array of characters terminated by the \0 (NUL) character.
What the above code does is to pass in the address of the first character in that array and the function populates the four characters starting from there.
In C, a pointer to char isn't necessarily a string. In other words, just because you have char *x;, it doesn't mean that x is a string.
To be a string, x must point to a suitably allocated region which has a 0 in it somewhere. The data from the first character that x points to and up to the 0 is a string. Here are some examples of strings in C:
char x[5] = {0}; /* string of length 0 */
char x[] = "hello"; /* string of length 5, the array length being 6 */
char *x = "hello"; /* string of length 5. x is a pointer to a read-only buffer of 6 chars */
char *x = malloc(10);
if (x != NULL) {
strcpy(x, "hello"); /* x is now a string of length 5. x points
to 10 chars of useful memory */
}
The following are not strings:
char x[5] = "hello"; /* no terminating 0 */
char y = 1;
char *x = &y; /* no terminating 0 */
So now in your code, AFunc's first parameter, even though is a char * isn't necessarily a string. In fact, in your example, it isn't, since it only points to a memory that has one useful element, and that's not zero.
Depending upon how you want to change the string, and how the string was created, there are several options.
For example, if the myStr points to a writable memory, you could do something like this:
/* modify the data pointed to by 'data' of length 'len' */
void modify_in_place(char *data, size_t len)
{
size_t i;
for (i=0; i < len; ++i)
data[i] = 42 + i;
}
Another slightly different way would be for the function to modify data until it sees the terminating 0:
void modify_in_place2(char *data)
{
size_t i;
for (i=0; data[i]; ++i)
data[i] = 42 + i;
}
You are only dealing with chars and char pointers. None of the char pointers are valid strings as they are not null terminated.
Try defining a string and see what it looks like.
But what if the string was more than one char? How would the code look
differently? Thanks for any help
Ofcourse, you would modify the other characters as well, but in the exact same way you did the first time.
Declare a char array and pass its address
Modify values at those address
A char array would be a more clear term for a string.

Resources