2-D array in string creating erroneous output in C - c

I am trying to do something as simple as printing the reverse of a string .
EXAMPLE :
Hello World! This is me
Needed O/P:
me is This World! Hello
My code goes something like this:
#include<stdio.h>
#include<string.h>
int main(){
char *arr[20] ;
int i,j;
int size;
char *revarr[20];
printf(" enter the number of words\n");
scanf("%d",&size);
for(i=0;i<size;i++)
scanf("%s",&arr[i]);
for(i=0;i<size;i++)
{
printf("%s\n",&arr[size-1-i]); //overwritten words
revarr[i]=arr[size-1-i];
}
printf(" the reversed sentence is %s\n",(char *)revarr);
}
I except arr[0] , arr[1] etc to be separate entities but on printing and storing them they seem to be overlapping like this :
i/p:
Hello World
o/p:
World
HellWorld
the reversed sentence is WorlHell##$
I can't seem to figure out what is wrong!
Thanks in advance!
EDIT :
On printing
printf(&arr[0]);
printf(&arr[1]);
I get :
HellWorld
World
What I expected it to print is
Hello
World

You declared arr and revarr as array of char pointers. You need to dynamically allocate memory for their elements.
Also note that you do not need & in statements
scanf("%s",&arr[i]);
and
printf("%s\n", &arr[size-1-i]);
// ^No need of &
Here is the modified version of your code. Note that there is no need to use revarr to reverse the string.
#include<stdio.h>
#include<stdlib.h>
int main(){
size_t i, size;
printf("Enter the number of words\n");
scanf("%d", &size);
char *arr[size] ; // Variable length array. Supported by C99 and latter
for(i = 0; i < size; i++)
{
arr[i] = malloc(20); // Assumimg words are no longer than 20 characters
scanf("%s", arr[i]);
}
printf("The reversed sentence is:\n");
for(i = size-1; i >= 0; i--) // Run loop in reverse order and print words
printf("%s ", arr[i]);
}

You haven't allocated memory for arr[0], arr[1], etc. before using them to read strings in
scanf("%s",&arr[i]);
That is cause for undefined behavior. You need something like:
int main(){
char *arr[20] ;
int i,j;
int size;
char *revarr[20];
printf(" enter the number of words\n");
scanf("%d",&size);
for(i=0;i<size;i++)
{
// Allocate memory.
// make it large enough to hold the input
arr[i] = malloc(100);
scanf("%s", arr[i]);
}
for(i=0;i<size;i++)
{
revarr[i]=arr[size-1-i];
}
printf(" the reversed sentence is: ");
for(i=0;i<size;i++)
{
printf("%s ", revarr[i]);
}
printf("\n");
// Deallocate the memory.
for(i=0;i<size;i++)
{
free(arr[i]);
}
return 0;
}

This is a good approach for your problem :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
/* the string line will contain the line of the input */
char line[100];
/* read the string with the function f gets */
fgets(line,100,stdin);
/* the tab will contain all the string of the variable line */
char *tab[20];
/* the variable p will point to each string of the line */
char *p=NULL;
/* we extract the strings of the line via the function strtok */
p=strtok(line," ");
int nb=-1;
while (p!=NULL)
{
nb++;
/* we allocate a space memory fo every str ing */
tab[nb]=malloc(sizeof(char)*100);
strcpy(tab[nb],p);
p=strtok(NULL," ");
}
/* there is an exception with the last string of the line we need to take care o f it */
tab[nb][strlen(tab[nb])-1]='\0';
int i;
/* print the strings in reverse or der */
for (i=nb;i>=0;i--)
{
printf("%s ",tab[i]);
/* dont forget to free the space memory at the end of the prog ram */
free(tab[i]);
}
printf("\n");
return 0;
}

You need the following
#include <stdio.h>
#include <string.h>
int main(void)
{
size_t size;
printf( "enter the number of words: " );
scanf( "%zu", &size );
char arr[size][20];
char revarr[size][20];
for ( size_t i = 0; i < size; i++ ) scanf( "%s", arr[i] );
printf( "\n" );
for ( size_t i = 0; i < size; i++ ) strcpy( revarr[i], arr[size-i-1] );
printf( "the reversed sentence is" );
for ( size_t i = 0; i < size; i++ ) printf( " %s", revarr[i] );
printf( "\n" );
return 0;
}
If to enter
2
Hello World
then output will be
World Hello
Take into account that the code will be compiled only if your compiler supports C99. Otherwise you have to allocate memory dynamically for character arrays.
As for your code then it has undefined behaviour and in whole is invalid. You did not allocate memory for each element of arrays arr and revarr. You may not assign one array to another. Instead you have to use standard function strcpy and so on.

Related

My ouput for C differs from compiler to compiler

I am writing a function longestStrInAr() that takes in an array of strings str and size (>0) as parameters, and returns the longest string and also the length of the longest string.
If two or more strings have the same longest string length, then the first appeared string will be
returned to the calling function.
This is the main function:
#include <stdio.h>
#include <string.h>
#define N 20
char *longestStrInAr(char str[N][40], int size, int *length);
int main()
{
int i, size, length;
char str[N][40], first[40], last[40], *p, *result;
char dummychar;
printf("Enter array size: \n");
scanf("%d", &size);
scanf("%c", &dummychar);
for (i=0; i<size; i++) {
printf("Enter string %d: \n", i+1);
fgets(str[i], 40, stdin);
if (p=strchr(str[i],'\n')) *p = '\0';
}
result = longestStrInAr(str, size, &length);
printf("longest: %s \nlength: %d\n", result, length);
return 0;
}
This is the function I have to write:
char *longestStrInAr(char str[N][40], int size, int *length)
{
int i,j, len;
*length =0;
char *longstr;
for (i = 0; i< size; i++){
j = 0;
len = 0;
while (str[i][j]!='\0'){
len++;
j++;
if (len > *length){
*length = len;
longstr = str[i];
}
}
}
return longstr;
}
My test input is
Enter array size:
4
Enter string 1:
Kenny
Enter string 2:
Mary
Enter string 3:
Peter
Enter string 4:
Sun
In XCode, I am able to receive the correct output:
longest: Kenny
length: 5
But using 2 different online compilers, I get the output below on both occasions:
longest: Kenny
length: 6
Why does my length differ?
Thank you.
probably one of them is a windows based compiler.
there "\n" is tread as two characters \r and \n
\r is called as carriage return
\n is called as line feed.
with this you get a byte extra there.

Why fgets() doesn't read after the first element?

I am trying to do this programming project in the book i study:
Write a program that sorts a series of words entered by the user:
Enter word: foo
Enter word: bar
Enter word: baz
Enter word: quux
Enter word:
In sorted order: bar baz foo quux
Assume that each word is no more than 20 characters long. Stop reading when the user enters an empty word (i.e., presses Enter without entering a word). Store each word in a dynamically sllocated string, using an array of pointers to keep track of the strings.
After all words have been read, sort the array (using any sorting technique) and then use a loop to print the words in sorted order.
That is what i am trying:
#include <stdio.h>
#include <string.h>
#define MAX_LENGTH 20
int compare ( const void * p, const void * q);
int main (void){
int n;
printf("How many words do you want to write");
scanf("%d", &n);
fflush(stdin);
char * word[n];
for( int i = 0; i < n; i++){
fprintf(stdout , "Waiting for the word:");
if(fgets(word[i] , MAX_LENGTH +1 , stdin) == "\n")
break;
}
qsort((void *)word,n,sizeof(int),compare);
printf("Ordered list is:\n\n");
for( int i = 0; i < n; i++){
fprintf(stdout , "\t %s", word[i]);
}
}
int compare (const void * p, const void * q){
return strcmp( * (char**) p , * (char **) q);
}
Edit : question with italic is solved thanks to fellow coders here. My new issue is i can't read past the first element of array. And program closes itself.
C:\Users\Lenovo\Desktop\ogrenme\ch17>sorting
How many words do you want to write4
Waiting for the word:asd
C:\Users\Lenovo\Desktop\ogrenme\ch17>
And there is one single annoying error that keeps me prevented from completing the exercise and "chill" with rest of this challenging book:
sorting.c:20:5: warning: implicit declaration of function 'qsort' [-Wimplicit-function-declaration]
qsort((void *)word,n,sizeof(int),compare);
I did a small trial (definitely the code could be optimized)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void) {
int n = 0;
char **string_list;
char *tmp;
//allocate memory for the first element
string_list = (char**)malloc(sizeof(char*)*1);
//infinite loop
while ( 1 ) {
//allocate size of each element to a max of 20 chars
string_list[n] = (char*)malloc(sizeof(char)*20);
printf("Enter word : ");
fgets (string_list[n], 20, stdin);
//remove trailing return carriage
string_list[n][strlen(string_list[n]) - 1] = '\0';
//break the loop here if user enters empty string
if (strlen(string_list[n]) < 1) {
break;
}
//add counter
n++;
//add memory to contain another element
string_list = realloc(string_list, sizeof(char*)*(n+1));
}
printf("\n\nInitial List is:\n");
for (int i=0 ; i<n-1 ; i++) {
printf("%s - ", string_list[i]);
}
printf("%s\n\n", string_list[n-1]);
//sorting the list
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
if (strcmp(string_list[i], string_list[j]) < 0) {
tmp = string_list[i];
string_list[i] = string_list[j];
string_list[j] = tmp;
}
}
}
printf("Sorted List is:\n");
for (int i=0 ; i<n-1 ; i++) {
printf("%s - ", string_list[i], strlen(string_list[i]));
}
printf("%s\n\n", string_list[n-1], strlen(string_list[n-1]));
}
output
$ ./sort
Enter word : foo
Enter word : bar
Enter word : baz
Enter word : quux
Enter word :
Initial List is:
foo - bar - baz - quux
Sorted List is:
bar - baz - foo - quux

Defining size for string using a variable not working properly in for loop in C

I'm trying to reverse the string input entered by user, the problem here is in function *rev, when I use size = strlen(STR); to get the length of the string and pass it into the size of the revS[size] the program outputs some garbage value for reverse string! if I pass some value instead if size in revS[10] and run the program it works as expected. I Have checked the value of size as
printf("\nlength of string is: %d\n",size);
and it gives the correct value. I'm not getting where is it going wrong!
#include<stdio.h>
#include<string.h>
char *rev(char *);
int main()
{
char string[100];
printf("Enter the string to reverse: ");
scanf("%s", string);
printf("You entered string : %s\n Reversed string is: %s", string, rev(string));
}
char *rev(char *STR)
{
int size, i, j = 0;
size = strlen(STR);
printf("\nlength of string is: %d\n", size);
char revS[size];
for(i = size-1; i >= 0; i--)
{
revS[j] = STR[i];
j = j + 1;
}
revS[j] = '\0';
return (revS);
}
OUTPUT:
Enter the string to reverse: mahaveer
length of string is: 8
You entered string : mahaveer
Reversed string is: ╚²b
--------------------------------
Process exited after 28.7 seconds with return value 0
Press any key to continue . . .
The issue is that your reversed string is allocated on the stack rather than the heap. When your rev function returns, all of the variables in that scope will be garbage collected. You can use malloc() to allocate memory dynamically on the heap. Note that the caller is responsible for calling free() on the string to avoid a memory leak.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *rev(char *);
int main() {
char string[100];
printf("Enter the string to reverse: ");
scanf("%s", string);
char *r = rev(string);
printf("You entered string: %s\nReversed string is: %s\n", string, r);
free(r);
}
char *rev(char *str) {
int i, j;
int size = strlen(str);
char *rev = malloc(sizeof(*rev) * (size + 1));
for (i = size - 1, j = 0; i >= 0; i--, j++) {
rev[j] = str[i];
}
rev[size] = '\0';
return rev;
}
Note that this code is susceptible to buffer overflows.
You have tho major UBs here. First you allocate local storage array which is not available after the function return. The second one - the size is too small to accomodate the string plus terminating zero

Storing scanf values into a 2d string array

I am having trouble storing strings into a 2d array using scanf.
To illustrate, this is the input the program accepts:
p2/src/stuff:5:
p3/src/stuff:5:
p4/src/stuff:6:
So I want to be able to split the strings and numbers by colons and store them separately. So ideally, my 2d array would look like this for strings:
[["p2/src/stuff"], ["p3/src/stuff"], ["p4/src/stuff"]]
Numbers can be stored in a 1d array.
Here is what I have so far:
int main() {
char *str;
char *i;
int n = 1;
while (n == 1) {
n = scanf("%m[^':']:%m[^':']:", &str, &i);
}
printf("# inputs read: %d\n", n);
printf("%s\n", str);
printf("%s\n", i);
}
Here it only prints the first line:
p2/src/stuff
5
Should I have an iterator that dose pointer arithmetic? I'm not familiar with pointer arithmetic.
scanf returns the number of items scanned. In this case it would be 2 instead of 1. Here a return of 1 would indicate a problem during the scan.
The %m specifier allocates memory to the pointers. Using a single pair of pointers, they should be freed in eadh iteration of the loop. You could use an array of pointers to store each of the inputs.
The scanset does not need the single quotes [^':']. If you are scanning for all characters that are not a colon [^:] will work.
EOF will terminate the while loop so if you are reading from a file, it will stop at the end of the file. Reading from stdin could be terminated using Ctrl+D (Linux) or Ctrl+Z (Windows).
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *str;
char *i;
int n;
while ( ( n = scanf("%m[^:]:%m[^:]:", &str, &i)) == 2) {
printf("# inputs read: %d\n", n);
printf("%s\n", str);
printf("%s\n", i);
free ( str);
free ( i);
}
return 0;
}
EDIT:
This uses an array of pointers to collect several inputs to the str and i arrays.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *str[10];// array of pointers
char *i[10];
int each = 0;
int loop = 0;
int n = 0;
while ( ( n = scanf("%m[^:]:%m[^:]:", &str[each], &i[each])) == 2) {
printf("# inputs read: %d\n", n);
printf("%s\n", str[each]);
printf("%s\n", i[each]);
each++;
if ( each > 9) {
break;//too many inputs for array size
}
}
for ( loop = 0; loop < each; loop++) {
printf ( "str[%d]=%s\n", loop, str[loop]);//print all the str inputs
}
for ( loop = 0; loop < each; loop++) {
printf ( "i[%d]=%s\n", loop, i[loop]);//print all the i inputs
}
for ( loop = 0; loop < each; loop++) {//free memory
free ( str[loop]);
free ( i[loop]);
}
return 0;
}
You have a few issues here.
First, while you should be using character pointers, you never allocate any memory for them. Next, when you use scanf, you should not be passing the address of the pointers but the pointers themselves. This is an easy mistake to make since you must pass the address when using scanf with integer types.
int main() {
char str[255];
char i[255];
int n = 1;
while (n == 1) {
n = scanf("%m[^':']:%m[^':']:", str, i);
}
printf("# inputs read: %d\n", n);
printf("%s\n", str);
printf("%s\n", i);
}

Split a string between words and insert newlines

i have a string that is made out of a few sentences.
for example:
hello world bye bye
now, i need to make this sentence into a coulmn of words:
hello
world
bye
bye
i have this idea going on, but i dont know how to write it correctly, so i was hopiny ypu guys could help me out.
this is what i have so far:
int len=0, k=0, stopatspace=0;
char temptext[100][15]={0};
char line[300]={0};
len=strlen(line);
printf("len is: %d", len);
for(k=0; k<len; k++)
{
if (k == ' ')
{
// i dont know what to write here in order to make it a cloumn
}
}
basiclly, my idea is to run on all the length of my line and when i reach a space i want it to enter (to go one line down so that it will look like a coulmn)
Suppose line is the char array that contains hello world bye bye and text is declared as
char text[100][15]; //I used 100 and 15 because your example contains it
and you want each word to be copied into each row of text. Then,use strtok() function with " "(space) as delimeter and place this in a loop that terminates when strtok() returns NULL to get each word. Copy each word to each row of text using strcpy() in the loop.
The code for this will look like this:
char text[100][15];
char line[]="hello world bye bye";
int i=0;
char *token=strtok(line," ");
while(token!=NULL)
{
strcpy(text[i],token);
i++;
token=strtok(NULL," ");
}
Now, to print it,you can use
for(int j=0;j<i;j++)
printf("text[%d]=%s",j,text[j]);
Another method would be to manually copy each character until a space is seen.
int len=strlen(line);
int i=0;
int k=0;
for(int j=0;j<len+1;j++)
{
if(line[j]==' ')
{
text[i][k]='\0';
i++;
k=0;
}
else
{
text[i][k]=line[j];
k++;
}
}
Note that the above code does not prevent buffer overflows. You can print each word using
for(int j=0;j<i+1;j++)
printf("text[%d]=%s",j,text[j]);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char string[100];
fgets(string, 100, stdin);
string[strlen(string)-1] = 0;
// create an array of pointers
char **string_array = (char**)malloc(sizeof(char*));
int i = 0, array_size;
// tokenize input
char *token = strtok(string, " ");
while(token!=NULL) {
// dynamically increase the array during run time
string_array = (char**)realloc(string_array, (i+1)*sizeof(char**));
// create the string as you would do when there is only one string
string_array[i] = (char*)malloc(strlen(token)+1);
strcpy(string_array[i], token);
token = strtok(NULL, " ");
i++;
}
array_size = i;
for(i=0; i<array_size; i++) {
printf("%s\n", string_array[i]);
}
return 0;
}
Basically you create an array of pointers and you allot memory for the strings one by one as you would do when there is only one string.
(if number of token is unknown, use realloc to increase the size of pointer to pointers.)
#include <stdio.h>
#include <ctype.h>
int main(void){
char line[300] = "hello world bye bye\n";
char temptext[100][15]={0};
int i=0, j, k=0;
while(line[k]){
if(isspace(line[k])){
++k;//skip space to word
continue;
}
for(j=0; j < 15-1 && line[k] && !isspace(line[k]); ++k, ++j)
temptext[i][j] = line[k];
if(j && ++i == 100)
break;
}
for(j=0; j<i; ++j)
puts(temptext[j]);
return 0;
}
#include<stdio.h>
#define NEWLINE printf("\n")
int main(void)
{
char string[]="hello world bye bye";
int index=0;
while(string[index])
{
if(string[index]==32)
{
NEWLINE;
index++;
}
else
{
printf("%c",string[index]);
index++;
}
}
NEWLINE;
}
// Whenever i encountered with a space, i am printing a new line on the screen. Here 32 is the ASCII value for space

Resources