at the moment, I'm trying some pointer stuff in C. But now, I have a problem with a pointer array. By using my code below, I get a strange output. I think there is a big mistake in the code, but I can't find it.
I just want to print the strings of the pointer array.
#include <stdio.h>
int main(void)
{
char *words[] = {"word1", "word2", "word3"};
char *ptr;
int i = 0;
ptr = words[0];
while(*ptr != '\0')
{
printf("%s", *(words+i));
ptr++;
i++;
}
return 0;
}
Output: word1word2word3Hã}¯Hɡ
Thanks for helping.
while(*ptr != '\0')
{
printf("%s", *(words+i));
ptr++;
i++;
}
initially, ptr points to the 'w' in "word1". So the loop iterates five times until *ptr == '\0'. But the array words contains only three elements, thus the fourth and fifth iteration invoke undefined behaviour and garbage is printed when the bytes after the words array are interpreted as pointers to 0-terminated strings. It could easily crash, and if you try it on other systems, with other compilers or compiler settings, it will sometimes crash.
You could translate the loop to
for(i = 0; i < strlen(words[0]); ++i) {
printf("%s", words[i]);
}
to see more easily what it does.
If you want to print out the strings in the words array, you can use
// this only worls because words is an actual array, not a pointer
int numElems = sizeof words / sizeof words[0];
for(i = 0; i < numElems; ++i) {
printf("%s", words[i]);
}
As words is an actual array, you can obtain the number of elements it contains using sizeof. Then you loop as many times as the array has elements.
I think you intended ptr to iterate through the items in the words array, but in fact it is actually iterating through the characters of "word1". To iterate through the words array, while pretending to not know the number of items to iterate through, then change the while condition as follows:
int main(void)
{
char *words[] = {"word1", "word2", "word3"};
char numWords = sizeof(words) / sizeof( words[0]);
int i = 0;
while(i < numWords)
{
printf("%s", *(words+i));
i++;
}
return 0;
}
If you really want to use ptr to iterate through the items of the words array, then change the words array and the while condition as follows:
int main(void)
{
char *words[] = {"word1", "word2", "word3", NULL};
char *ptr[] = words;
int i = 0;
while(ptr[i] != NULL)
{
printf("%s", *(words+i));
i++;
}
return 0;
}
Related
I did this program to reverse the order of the words in the give string. (And it works)
i.e. Output: sentence first the is This
However I am stuck when it comes to adding another sentence to the array.
For example I need to have an array {"This is the first sentence", "And this is the second"} producing as output: sentence first the is This , second the is this And
int main() {
char str[] = {"This is the first sentence"};
int length = strlen(str);
// Traverse string from end
int i;
for (i = length - 1; i >= 0; i--) {
if (str[i] == ' ') {
// putting the NULL character at the position of space characters for
next iteration.
str[i] = '\0';
// Start from next character
printf("%s ", &(str[i]) + 1);
}
}
// printing the last word
printf("%s", str);
return 0;
}
I am new to C so its not surprising that I got stuck even if the solution is quite easy. Any help would be appreciated! Thanks!
Since you already have the code to print the words of one string in reverse order, I would suggest making that a function which takes a single string as an argument, i.e.:
void print_words_reverse(char * const str) {
// your current code here
}
Then you can call it separately for each string:
char strings[][30] = {
"This is the first sentence",
"And this is the second"
};
for (int i = 0; i < sizeof(strings) / sizeof(*strings); ++i) {
print_words_reverse(strings[i]);
}
Note that since you are modifying the string (by replacing spaces with NUL bytes), the argument needs to be modifiable, which means you are not allowed to call it (in standard C) with a pointer to a string literal, which means you can't simply use const char *strings[] = { "first", "second" }. You could get rid of the ugly constant length (here 30) reserved for every string by making your code not modify the argument string. Or you could have a separate char array for each sentence and then use pointers to those (modifiable) strings.
First, you can try with a two-dimensional array or use an array of pointers.
Secondly, in your approach, you lose the initial value of your string, I don't know how important it is.
This is my fast approach using arrray of pointers.
#include <stdio.h>
#include <string.h>
static void print_word(const char *str)
{
for (int i = 0; str[i] && str[i] != ' '; i++)
printf("%c", str[i]);
putchar(' ');
}
int main(void)
{
int len;
const char *str[] = {"This is the first sentence",
"And this is second", NULL};
for (int i = 0; str[i]; i++) {
for (len = strlen(str[i]); len >= 0; len--) {
if (len == 0)
print_word(&str[i][len]);
else if (str[i][len] == ' ')
print_word(&str[i][len + 1]);
}
putchar('\n');
}
printf("Initial value of array of strings [%s | %s] \n", str[0], str[1]);
return 0;
}
output is:
sentence first the is This
second is this And
Initial value of array of strings [This is the first sentence | And this is second]
I suggest you using memcpy but without altering too much your code this seems to work
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_STRING_LENGTH 100
int main()
{
char *str[] = {"This is the first", "And this is the second sentence"};
const size_t NUM_STRING = sizeof(str)/sizeof(char*);
/*%z used to print size_t variables*/
printf("%zd strings found\n", NUM_STRING);
int length[2];
int i;
for (i=0; i<NUM_STRING; i++)
{
length[i] = strlen(str[i]);
}
printf("length initialized %d %d\n", length[0], length[1]);
// Traverse string from end
int j = 0;
char temp[MAX_STRING_LENGTH];
printf("\n\n");
for (j=0; j<NUM_STRING; j++)
{
/*Make sure the string respect the MAX_STRING_LENGTH limit*/
if (strlen(str[j])>MAX_STRING_LENGTH)
{
printf("ERROR: string %d exceding max string length %d defined in constant "
"MAX_STRING_LENGTH. Exiting from program.\n", j, MAX_STRING_LENGTH);
exit(1);
}
//reset temporary string
memset(temp, '\0', sizeof(temp));
//printf("temp variable reinitialized\n");
for (i = length[j] - 1; i >= 0; i--)
{
temp[i] = str[j][i];
if (str[j][i] == ' ')
{
// putting the NULL character at the position of space characters for next iteration.
temp[i] = '\0';
// Start from next character
printf("%s ", &(temp[i]) + 1);
}
}
// printing the last word
printf("%s ", temp);
}
printf("\n");
return 0;
}
i want to type a sequence of chars and save them with a temporary array. After that, i want to create the actual array with a certain size with the values of the temporary array. Here is the code:
#include <stdio.h>
int main()
{
char c;
char temp[100];
char array[24];
int i;
char *ptrtemp = temp;
// create a temporary array with getchar function
while(1) {
c = getchar();
if(c == '\n')
break;
*ptrtemp = c;
i++;
ptrtemp++;
}
// type wrong in case of wrong size
if(i != 24) {
printf("Data is wrong");
exit(0);
}
char *ptrarray = array;
char *ptrtemp2 = temp;
// create the actual array
for(i=0;i<24;i++) {
*ptrarray = *ptrtemp2;
if(i == 23)
break;
ptrarray++;
ptrtemp2++;
}
//printing the actual array
printf("\n%s\n", array);
}
However, I get interesting elements after the actual sequence. The array's size was stated as 24 but 25th, 26th, 27th etc. elements are being also printed.
Here is what I get
Every time I try, I see different extra chars. Can anyone explain what is happening here?
You are doing the stuff far too complicated.
First, as already denoted, i is not initialised. Second, you do not leave space for the terminating 0 in the array. Finally, you can easily write to your array directly:
char array[24 + 1]; // need space for the terminating 0 character
for(int i = 0; i < 24; ++i)
{
// write to array directly:
array[i] = getchar();
if(array[i] == '\n')
{
printf("Data is wrong");
return 0;
}
}
array[24] = 0; // this is important if using %s!
printf("\n%s\n", array);
Actually, you have an alternative, as you know you always want to print exactly 24 characters:
char array[24]; // skipping(!) space for the terminating 0 character
for(int i = 0; i < 24; ++i)
{
// just as above
}
// NOT now (would be UB, as array is too short):
// array[24] = 0;
// but now need to give precision to tell how many bytes to write
// (maximally; if a terminating 0 would be encountered before,
// printf would stop there)
printf("\n%.24s\n", array);
I modified the following:
Initialized i to 0 in the beginning.
memset(temp, 0, sizeof(temp));
Added following to make sure that it does not cross array boundary.
if (i == 99)
{
break;
}
Similarly added following for array variable.
memset(array, 0, sizeof(array));
Following check is done beginning of for loop to make sure it does not write to 24th element of array.
if(i == 23)
break;
#include <stdio.h>
int main()
{
char c;
char temp[100];
char array[24];
int i = 0; //Should be initialized to 0
char *ptrtemp = temp;
memset(temp, 0, sizeof(temp));
// create a temporary array with getchar function
while(1) {
c = getchar();
if(c == '\n')
break;
*ptrtemp = c;
i++;
ptrtemp++;
if (i == 99)
{
break;
}
}
char *ptrarray = array;
char *ptrtemp2 = temp;
memset(array, 0, sizeof(array));
// create the actual array
for(i=0;i<24;i++) {
if(i == 23)
break;
*ptrarray = *ptrtemp2;
ptrarray++;
ptrtemp2++;
}
//printing the actual array
printf("\n%s\n", array);
}
Let me know if you face any problem.
Two problems:
You are using i uninitialized in your code. (I don't think the issue you are seeing is because of that)
All C-strings need to be '\0' terminated. In order to ensure that it is the case, you can always do a:
memset(array, 0, sizeof(array));
This program is supposed to dynamically store each string entered into a pointer. Each pointer is part of an array of pointers that will collectively hold all of the strings. When the user enter an empty word, or NULL, it is supposed to quit. My problem is that the code just skips over the NULL conditional statement. I saw some similar posts and have been at it for hours but just can't solve it.
#include <stdio.h>
#include <string.h>
void readWord(char wordChar[], int MAX_CHARS);
int main()
{
int MAX_CHARS = 20;
int wCount = 0;
char *wordArray[wCount]; // Array of pointers that will each point to wordChar
char wordChar[MAX_CHARS];
int i;
for(i = 0;;i++)
{
wCount++;
printf("Enter word: ");
readWord(wordChar, MAX_CHARS); //Reads one word at a time
//Dynamically store each
wordArray[i] = (char*) malloc((int) strlen(wordChar) * (int) sizeof(char));
wordArray[i] = wordChar;
printf("%s \n", wordArray[i]); //Troubleshooting *********************
// If loop ends scanning when word is NULL
if(wordArray[i] == 'NULL')
{
printf("if loop");
break;
}
else printf("no loop");
}
}
/***********************************************************/
void readWord(char wordChar[], int MAX_CHARS)
{
int letter, i = 0;
while((letter = getchar()) != '\n')
{
if(i < MAX_CHARS)
{
wordChar[i] = letter;
i++;
}
}
wordChar[i] = '\0';
}
The short and useless summary is: you're #includeing string.h; use it!
You're trying to compare two pointers directly.
if(wordArray[i] == 'NULL')
This line looks at the pointer value of wordArray[i] to the value of the multi-character literal 'NULL' (note that I didn't say string: you used single quotes here, so 'NULL' has the integer value 0x4e554c4c; see https://stackoverflow.com/a/7459943/510299). If wordArray[i] points to the address 0x12345678, then this is comparing 0x12345678 to 0x4e554c4c and sees that they're not equal.
What you want is to compare strings. In C, you can't do this with == because C strings are char arrays or pointers to chars; == compares the pointer (address) value, as I noted above.
Solution, use strcmp.
if(strcmp(wordArray[i], "NULL") == 0)
(Note the use of double quotes.)
EDIT: Also note that char *wordArray[wCount]; is declared when wCount == 0. This nominally means you tried to declare an array of length 0, which is undefined behaviour. You need to declare wordArray with some length (probably the maximum number of words you can store). [Thanks to riodoro1 for pointing this out in a comment.]
You made a similar blunder with string manipulation in C here:
wordArray[i] = (char*) malloc((int) strlen(wordChar) * (int) sizeof(char));
This line sets the pointer wordArray[i] to some newly allocated memory.
wordArray[i] = wordChar;
This line then proceeds to change the pointer wordArray[i] to point to the original location where the read word was stored. Oops. The next time you go through this loop, wordChar changes, and wordArray[i] is pointing to wordChar... so the new word "replaces" all the previous words.
Solution? You need to copy the string to the memory you just malloc'd. Use strcpy().
printf("if loop");
A conditional (if) statement is not a kind of loop.
#include <stdio.h>
#include <stdlib.h> //for realloc and free (malloc)
#include <string.h>
void readWord(char wordChar[], int MAX_CHARS);
int main(void){
int MAX_CHARS = 20;
int wCount = 0;
char **wordArray = NULL; // Array of pointers that will each point to wordChar
char wordChar[MAX_CHARS];
int i;
for(i = 0;;i++){
printf("Enter word: ");
readWord(wordChar, MAX_CHARS); //Reads one word at a time
if(*wordChar == '\0' || strcmp(wordChar, "NULL") == 0){//empty word or "NULL"
putchar('\n');
break;
}
wCount++;
wordArray = realloc(wordArray, wCount * sizeof(*wordArray));//check omitted
//Dynamically store each
wordArray[i] = malloc(strlen(wordChar) + 1);//+1 for NUL
strcpy(wordArray[i], wordChar);//copy string
}
//check print and free
for(i = 0; i < wCount; ++i){
printf("'%s'\n", wordArray[i]);
free(wordArray[i]);
}
free(wordArray);
return 0;
}
void readWord(char wordChar[], int MAX_CHARS){
int letter, i = 0;
while((letter = getchar()) != '\n' && letter != EOF){
if(i < MAX_CHARS -1)//-1 for NUL, or char wordChar[MAX_CHARS+1];
wordChar[i++] = letter;
else
;//drop letter upto newline
}
wordChar[i] = '\0';
}
What I am trying to do is check if the word entered by the user has first five alphabetical letters and if it has, I need to copy those letters to another array.But it gives me an error saying "passing argument 1 of strcpy makes pointer from integer without cast[enabled by default]".
char s1[100];
char a1[100];
char alpha[5]={'a','b','c','d','e'};
int i,j,k=0;
printf("Enter a word");
fgets(s1,100,stdin);
for(i=0;i<strlen(s1);i++)
{
for(j=0;j<5;j++)
{
if(s1[i]==alpha[j])
{
strcpy(a1[k],s1[i]);
k++;
}
}
}
Need help to figure out what is wrong with this
strcpy has two input parameters char *. You can't use it for two characters. If you want to copy one character from one array to another then you need to use = operator as a1[k] = s1[i]
You only need one loop:
Replace char by char:
for(i = 0; i < strlen(s1); i++)
{
a1[i] = s1[i];
}
Or, use strcpy like this: strcpy(a1, s1);
Answering your comment:
I tried a1[k]= s1[i] but it displays some vague characters for a1 ex-: if s1 is "abc" , a1 displays as "abc!"
C strings need to be null terminated.
Try doing this:
char s1[100] = {0};
char a1[100] = {0};
Small example:
#include <string.h>
#include <stdio.h>
int main()
{
char s1[100] = {0};
char a1[100] = {0};
int i,j,k=0;
printf("Enter a word: ");
fgets(s1,100,stdin);
for(i = 0; i < strlen(s1); i++)
{
a1[i] = s1[i];
}
printf("a1 now contains: %s", a1);
return 0;
}
I have written a C program. It's a character counting program. I will give input as below
Input: ABCAPPPRC
And need as output: A2B1C2P3R1.
But it gives output as A2B1C2A1P3P2P1R1C1. It basically doing as per the logic I have written in program. But I don't want to count the characters of string which have already been counted. Can you suggest what logic I should implement for this?
#include <stdio.h>
int main()
{
char str[30]= "ABCAPPPRC";
char strOutPut[60]="";
char *ptr= &str, *ptr2=&str;
char ch='A';
int count=0;
puts(str);
while (*ptr !=NULL)
{
count =0;
ch = *ptr;
while (*ptr2!= NULL)
{
if (*ptr2 == ch) count++;
ptr2++;
}
printf("%c%d",*ptr, count);
ptr++;
ptr2 = ptr;
}
}
You need to separate the counting from the printing.
The first loop goes through the input and counts the number of occurrences of each character, storing the counts in an array indexed by the character code.
The second loop goes through the array of counts and prints the character corresponding to a non-zero count followed by that count.
For example:
#include <stdio.h>
int main(void)
{
char str[] = "ABCAPPPRC";
int counts[256] = { 0 };
puts(str);
for (char *ptr = str; *ptr != '\0'; ptr++)
counts[(unsigned char)*ptr]++;
for (int i = 0; i < 256; i++)
{
if (counts[i] != 0)
printf("%c%d", i, counts[i]);
}
putchar('\n');
return(0);
}
Sample output:
ABCAPPPRC
A2B1C2P3R1
I could not understand the first for loop. Could you please explain it?
The for control line steps through the string str one character at a time. It is the for loop equivalent of the outer while loop in your original code.
char *ptr = str;
...
while (*ptr != '\0')
{
...
ptr++;
}
The body of the loop converts *ptr (a plain char) into an unsigned char (so that it is guaranteed to be positive), and then uses that value as an index into the array counts. Thus, for example, on the first iteration, A is mapped to 65, and counts[65] is incremented. Thus, for each character code, the loop increments the count corresponding to that character code each time the character is encountered in the string.
The second loop then picks out the non-zero counts, printing the character code as a character followed by its count.
(Incidentally, you should have been getting a compilation warning from the original char *ptr = &str about a type mismatch between char * and char (*)[30]. Learn when to put ampersands in front of array names — you seldom do it unless there is also a subscript after the array name. Thus, &array is usually — but not always — wrong; by contrast, &array[0] is very often valid. Also note that on some machines, NULL is defined as ((void *)0) and this elicits a warning when you compare it to a plain char, as you did with while (*ptr != NULL). You should compare characters to '\0' as in my rewrite; you should reserve NULL for use with pointers.)
str is alerady a character pointer, so when you do this: char *ptr= &str you convert a pointer to pointer to character to a char*. Loose the ampersand(&).
Also in the inner cycle you should check if the given value of ch has already been processed. In the case you use when ptr is pointing to the second A you should just continue, because you have already added the number of A-s in the answer.
Your solution is far from optimal. I strongly suggest you lookup counting sort. It will make your solution faster but also will make it simpler.
# Jonathan your solution is correct only when string characters are given in ascending order like ABCDEF, but it gives problem when character order is changed. Input string is "ABAPPPRCC" and required output is A2B1P3R1C2.
Here in this case your solution will change out put to A2B1C2P3R1.
Below program gives character count without changing string formation.
char *str= "ABAPPPRCC";
char strOutPut[30]="";
char *ptr = str, *ptr2 = str;
char ch='A';
int count=0, i = 0 , total_print = 0;
puts(str);
while (*ptr != '\0')
{
count =0;
ch = *ptr;
while (*ptr2!= '\0')
{
if (*ptr2 == ch) count++;
ptr2++;
}
for( i = 0; i < total_print ; i++ )
{
if ( ch == strOutPut[i] )
{
i = total_print + 1;
break;
}
}
if( i <= total_print )
{
printf("%c%d",*ptr, count);
strOutPut[total_print++] = ch;
}
ptr++;
ptr2 = ptr;
}
#include <stdio.h>
int main(void){
const char noncountchar = '\x11';
char str[30]= "ABCAPPPRC";
char strOutPut[60]="";
char *ptr, *ptr2;
char ch;
int count=0, len=0;
puts(str);
for(ptr=str;ch=*ptr;++ptr){
if(ch == noncountchar) continue;
count =1;
for(ptr2=ptr+1;*ptr2;++ptr2){
if (*ptr2 == ch){
*ptr2 = noncountchar;
++count;
}
}
len += sprintf(strOutPut+len, "%c%d", *ptr, count);
}
printf("%s", strOutPut);
return 0;
}