I'm trying to write a simple program that reads user entered strings into an array of pointers. The reading goes fine, however when I want to add an extra parameter to my method in order to save how many Strings I actually read, it stops working. The compiler isn't very helpfull so I decided to take my problem here.
Actual code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void read(char**, int *);
void write(char**);
int main() {
int amount = 0;
int * amount_p = &amount;
char *pt_p[1000];
read(pt_p,amount_p);
write(pt_p);
}
void read(char ** pt, int * amount) {
char stop[] = "STOP";
char* woord;
int i = 0;
printf("Enter a word: ");
scanf("%70s", woord);
pt[i] = malloc(sizeof(char)*(strlen(woord)+1));
pt[i] = strcpy(pt[i], woord);
i++;
while(strcmp(stop,pt[i-1]) != 0) {
printf("Enter a word: ");
scanf("%70s", woord);
pt[i] = malloc((strlen(woord)+1)*sizeof(char));
pt[i] = strcpy(pt[i], woord);
i++;
}
*amount = i;
}
void write(char ** pt) {
int i = 0;
char stop[] = "STOP";
while(strcmp(stop,pt[i]) != 0 ) {
printf("pt[%d]-> %s",i,pt[i]);
printf("X \n");
i++;
}
}
you need to allocate some space where you can enter the string
char* woord; is just declaring a pointer that points nowhere in particular.
instead declare it as
char woord[128];
to allocate 128 bytes on the stack for your input.
also use fgets() instead of scanf() to read strings, that way you can prevent user from entering a too large string.
if ( fgets( woord, sizeof(wooord), stdin ) != NULL )
{
char* p = strchr( woord, '\n' );
if (p != NULL )
{
*p = '\0';
}
}
Related
I have a task to do. I have to work with strings. I will show you the input and output, because I think that will be clear what the task is.
Input: "aaa bbuvvvvo"
Output: "a$3 b$2uv$4o"
If there is the same symbols, I have to leave that symbol and then put dollar sign '$' and an integer of how many same signs was there. I am stuck on the spot, where I have to change string without losing any information.
I will leave my code here, it might help.
#include <stdio.h>
#include <string.h>
#define CAPACITY 255
#define MAX_NUMBER 10
void Output(char readFile[], char outputFile[], char string[]);
void changeString(char string[], char newString[]);
int main() {
char readFile[CAPACITY];
char outputFile[CAPACITY];
char string[CAPACITY];
// Input file's name
printf("Iveskite teksto failo varda: ");
scanf("%s", &readFile);
// Output file's name
printf("Iveskite teksto faila i kuri bus isvedamas atsakymas: ");
scanf("%s", &outputFile);
Output(readFile, outputFile, string);
return 0;
}
// Scanning file
void Output(char readFile[], char outputFile[], char string[])
{
char newString[CAPACITY];
FILE *input, *output;
input = fopen(readFile, "r");
while(fscanf(input, "%s", string) != EOF)
{
changeString(string, newString);
printf("%s\n", newString);
}
}
// Changing string to wanted string
void changeString(char string[], char newString[])
{
char number[MAX_NUMBER];
int symbols = 0;
int j;
for(int i = 0; string[i] != '\0'; ++i)
{
int temp = i;
newString[i] = string[i];
if(newString[i] == string[i + 1])
{
j = i;
while(string[j] == string[i])
{
++symbols;
++j;
}
// Changing int to char
sprintf(number, "%d", symbols);
newString[i + 1] = '$';
i += 2;
newString[i] = number[0];
symbols = 0;
}
}
}
I have tried to do that with function called changeString, but I get the wrong output all the time. Also the input I am getting is from .txt file.
EDIT: When I compiling this program right now, I get a$3 b$2v$4vo that output.
For starters this declaration in main
char string[CAPACITY];
does not make sense.
You should declare variables in scopes where they are used.
The variable string is used in the function Output where it is should be declared.
The function changeString should be declared like
void changeString( const char string[], char newString[]);
because the source string is not changed within the function.
Your function has several bugs.
For example it does not build a string in the array newString because it does not append the stored sequence in the array with the terminating zero character '\0'.
Secondly this increasing of the variable i
i += 2;
in general is invalid. You need to add to the variable i the number of repeated characters in the source string.
Or the number of repeated characters change greater than or equal to 10. In this case this statement
newString[i] = number[0];
will not produce correct result.
The function can be defined the following way as shown in the demonstration program below.
#include <stdio.h>
#define CAPACITY 255
void changeString( const char string[], char newString[] )
{
while ( *string )
{
*newString++ = *string;
size_t n = 1;
while (*++string == *( newString - 1 ) ) ++n;
if (n != 1)
{
*newString++ = '$';
int count = sprintf( newString, "%zu", n );
newString += count;
}
}
*newString = '\0';
}
int main( void )
{
char string[CAPACITY] = "aaa bbuvvvvo";
char newString[CAPACITY];
changeString( string, newString );
puts( newString );
}
The program output is
a$3 b$2uv$4o
I am writing some C Code where the user enters the desired string size and then a string which will be reversed then printed (as opposed to being printed in reverse.) I also would like to mention that I don't want to use external libraries, the whole point of this is to be able to do it manually. I used dynamic memory allocation to create a string of a size inputted by the user and called a "Reverse Array" function. Everything works fine until the function is called. My method for reversing the string followed the same principle as reversing a normal array but instead of moving integers around I moved characters around. Can you explain to me what I have done wrong?
My Code:
#include <stdio.h>
#include <stdlib.h>
int RvsArr(char *Str, int end)
{
int start = 0;
char tmp;
while (start < end)
{
tmp = Str[start];
Str[start] = Str[end];
Str[end] = tmp;
start++;
end--;
}
printf("%s", Str);
return 0;
}
int main()
{
int ArrSz;
printf("Please enter array size: ");
scanf("%i", &ArrSz);
char *Str;
Str = (char *)malloc(ArrSz * sizeof(char));
printf("Please enter your string: ");
scanf("%s", Str);
RvsArr(Str, ArrSz);
free(Str);
return 0;
}
You need to reverse the actual string, not the full buffer.
char *RvsArr(char* Str)
{
char *end, *wrk = Str;
char tmp;
if(wrk && *wrk)
{
end = Str + strlen(wrk) - 1;
while(wrk < end)
{
tmp = *wrk;
*wrk++ = *end;
*end-- = tmp;
}
}
return Str;
}
int main()
{
int ArrSz;
printf("Please enter array size: ");
scanf(" %i", &ArrSz);
char* Str;
Str = malloc(ArrSz * sizeof(char));
printf("Please enter your string: ");
scanf(" %s", Str);
printf("\n`%s`\n", RvsArr(Str));
free(Str);
return 0;
}
https://godbolt.org/z/azob5s
For starters the user can enter a string the size of which can be less than the size of the dynamically allocated character array that stores the string.
So passing the size of the array does not make a sense. The size of the array is not the same as the size of the entered string.
Also this expression Str[end] access memory beyond the allocated array in the first iteration of the while loop.
And the return type int also does not make a sense.
Apart from this the function should not output anything. It is the caller of the function that will decide to output the result string or not.
Pay attention to that this call
scanf("%s", Str);
is unsafe. It would be better to use the function fgets. For example
fgets( Str, ArrSz, stdin );
In this case you will need to remove the new line character '\n' that the function can append to the entered string.
Without using standard string functions the function can be defined the following way as it is shown in the demonstrative program below.
Instead of the senseless return type int the function returns a pointer to the first character of the reversed string.
#include <stdio.h>
char * RvsArr( char *s )
{
char *last = s;
while ( *last ) ++last;
if ( last != s )
{
for ( char *first = s; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main(void)
{
char s[] = "Hello World!";
puts( s );
puts( RvsArr( s ) );
return 0;
}
The program output is
Hello World!
!dlroW olleH
If you are allowed to use standard string functions then the function RvsArr can look the following way (provided that the header <string.h> is included)
char * RvsArr( char *s )
{
char *last = s + strlen( s );
if ( last != s )
{
for ( char *first = s; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
Character arrays or string in c(as it is generally referred to) requires one extra byte which store null character ('\o' or 0) to indicate the end of string. You can store ArrSz - 1 character in your array and ArrSz byte stores the termination character('\o' or 0).
int RvsArr(char* Str, int end)
{
if (Str == 0 || end <= 1)
return 0;
int start = 0;
char tmp;
while(start < end)
{
tmp = Str[start];
Str[start] = Str[--end]; // pre decrement the counter to last char
Str[end] = tmp;
start++;
}
printf("%s", Str);
return 0;
}
or in other version
int RvsArr(char* Str, int end)
{
if (Str == 0 || end <= 1)
return 0;
int start = 0;
int last = end - 1;
char tmp;
while(start < last)
{
tmp = Str[start];
Str[start] = Str[last];
Str[last] = tmp;
start++;
last--;
}
printf("%s", Str);
return 0;
}
And some changes in main function are
int main()
{
int ArrSz;
printf("Please enter array size: ");
scanf("%i", &ArrSz);
char *Str;
Str = (char *)malloc(ArrSz * sizeof(char));
printf("Please enter your string: ");
scanf("%s", Str);
Str[ArrSz] = '\0'; // Here we have no control on how many characters are read, scan is a security vulnerability becuse of this
printf("Input=%s, len=%d\n", Str, strlen(Str));
RvsArr(Str, strlen(Str));
free(Str);
return 0;
}
I'm trying to write program to ask user to enter First and Last Name. Then my program will result their Full Name (combined First + Last Name) and the length of their Full Name. My Output right now does empty Full Name and 0 length. I guess my problem is at display_name functions. Here is my code so far. Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void display_name(char *fullname);
int count_char( char*x_ptr);
char * get_name(char * first_name, char * last_name);
#define MAX 80 // maximum number of array elements
int main(void)
{
char first_name[MAX];
char last_name[MAX];
char *x_ptr;
system("cls");
printf("Enter Last Name: \n" );
scanf("%s", &last_name );
printf("Enter First Name: \n" );
scanf("%s", &first_name );
x_ptr = get_name(first_name, last_name);
display_name(x_ptr);
puts("");
system("pause");
return 0;
}
char * get_name(char *first_name, char *last_name)
{
static char fullname[MAX];
char x;
x = 0;
strcpy(fullname, first_name);
strcat(fullname, " ");
strcat(fullname, last_name);
while (((fullname[x] = getchar()) != '\n') && (x < (MAX-1)))
{
x++;
}
fullname[x] = '\0';
return(fullname);
}
/* Function to print out string passed to it and display the length of fullname*/
void display_name(char *fullname)
{
char *a;
printf("Your Full name is ");
a = &fullname[0];
while (*a != '\0')
{
putchar(*a);
a++;
}
int length;
length = strlen(fullname);
printf("\nHas %d Characters", length);
length = count_char(fullname);
printf("\nHas %d Non Space Characters", length);
}
/* function to return count of non space characters*/
int count_char( char * x_ptr)
{
char *b;
unsigned int count=0;
b = x_ptr;
while (*b != '\0')
{
if (*b != ' ')
count++;
b++;
}
return
(count);
}
scanf("%s", &last_name );
Compiler complained and you ignored it. It should be scanf("%s", last_name );. Same goes with firstname. Yours had type char (*)[] and scanf expects char* which is what we gave in second case.
This part is doing nothing that you would do to achieve what you are trying to do.
while (((fullname[x] = getchar()) != '\n') && (x < (MAX-1)))
This is using getchar to get the characters from stdin and put it in the char array where you are storing the concatenated name.
Using static char array is not a good solution. The next time you try to use this function - it will overwrite the data previously written by another function. Illustration implementation of the function get_name would be
char * get_name(char *first_name, char *last_name)
{
char *fullname = malloc(strlen(first_name)+2+strlen(last_name));
if(!fullname){
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(fullname, first_name);
strcat(fullname, " ");
strcat(fullname, last_name);
return fullname;
}
Benefit of using this implementation is that - now the data that is being used is not closely coupled with the methods that call this one. So it can be reused independent of it's previous usage in another function.
Also when using the function get_name remember to free the dynamically allocated memory when you are done working with it.
I am trying to build a program that uses dynamic allocation to build an array of strings.
After the user finishes to enter the words he wants into the array i want to print the array one word after the other. I am using pointers to pointers, however it doesn't seem to work:
#define SIZE 256
void paintWords(char **words, int count_words);
void main() {
char **words = NULL;
int flag = 1;
char buffer[SIZE];
int count_words = 0;
char *curr_word;
while (flag)
{
_flushall();
printf("Enter a word:");
gets(buffer);
words = (char**)realloc(words,++count_words*sizeof(char*));
curr_word = (char*)malloc(strlen(buffer) + 1);
words[count_words - 1] = curr_word;
printf("Do you wish to continue(0-no, 1-yes):");
scanf("%d", &flag);
}
paintWords(words, count_words);
}
void paintWords(char **words, int count_words) {
int j = 0;
for (int i = 0; i < count_words; i++)
{
printf("%s\n", words[i][j]);
}
}
Copy buffer to your malloc'ed block with strcpy
strcpy(curr_word, buffer);
you are discarding the read word since you don't put it anywhere
Don't use gets use fgets instead
fgets(buffer, sizeof(buffer), stdin);
this would prevent a buffer overflow.
This is just the jst which in your case is the 0th character of the word
printf("%s\n", words[i][j]);
change it to
printf("%s\n", words[i]);
turn compiler warnings on, it would tell you about printf expecting a char * and recieving char instead.
Also consider the following:
main() should return int.
You don't need to cast malloc.
Don't overwrite your pointer with realloc, use a temporary pointer and assign it to array on success only. Otherwise if realloc returns NULL you will not be able to free(array) for example.
++count_words
words = realloc(words,count_words*sizeof(char*));
words[count_words-1] = malloc(strlen(buffer) + 1);
strcpy(words[count_words-1],buffer);
Later print the array
printf("%s\n",words[i]);
realloc() can fail so
char *temp = realloc(words,count_words*sizeof(char*));
if(temp != NULL)
words = temp;
Few other fixes will be
You shouldn't be using gets which is no more a standard. Use fgets() and note that fgets() comes with a newline character
Check the code below:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define SIZE 256
void paintWords(char **words, int count_words);
void main() {
char **words = NULL,ch;
int flag = 1;
char buffer[SIZE];
int count_words = 0;
//char *curr_word;
while (flag)
{
printf("Enter a word:");
fgets(buffer,sizeof(buffer),stdin);
words = (char**)realloc(words,++count_words*sizeof(char*));
words[count_words - 1] = (char*)malloc(strlen(buffer) + 1);
strcpy(words[count_words-1],buffer);
printf("Do you wish to continue(0-no, 1-yes):");
scanf("%d", &flag);
while((ch = getchar()) != '\n');
}
paintWords(words, count_words);
}
void paintWords(char **words, int count_words) {
int i;
for (i=0; i < count_words; i++)
{
printf("%s", words[i]);
}
}
I'm new to C (coming from Java) and naturally that poses some difficulties. I would like to write just a short program that reads in char-Arrays from stdin and stores the individual strings in an array. After reading in the strings I just want to have them printed out, but that's when it gets really confusing for me.
Here's my code:
#include <stdlib.h>
#include <stdio.h>
int main(){
char **stringarray[2];
char buffer[5];
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
char *tmp = buffer;
stringarray[i] = &tmp;
i++;
}
for(int i = 0; i < 2; i++){
printf("%s\n", &stringarray[i]);
}
return 0;
}
The first part does in fact compiles (i.e. the part before the print out). I understand that my stringArray has to be an array of char pointers, because that's what a char array basically is in c. It's a pointer to the first character. At first I just wrote
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
stringarray[i] = buffer;
i++;
}
which also compiled, but of course then I have one pointer that points to buffer, which will only save the last string that has been read.
What do I have to do that I can store a simple array of strings?
I suggest you change your code as following.
#include <stdlib.h>
#include <stdio.h>
#include <string.h> /* to use strdup function */
int main(){
char *stringarray[2]; /* I don't understand why you use pointer to pointer than pointer, char **stringarray[2]; */
char buffer[6]; /* I suggest 6 than 5, because string has terminate byte in C */
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
stringarray[i] = strndup(buffer, 5);
i++;
}
for(int i = 0; i < 2; i++){
printf("%s\n", stringarray[i]); /* changed stringarray */
}
return 0;
}
char **stringarray[2]; is like char ***stringarray because an array is like a pointer to the first value of the array.
printf wants a char* and &stringarray[i] is a char**
if a string is an array then an array of strings is an array of array.
So the code is :
int main()
{
char stringarray[2][5];//array of (array of char)
char buffer[5];
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL)
{
strcpy(stringarray[i],buffer); //copies the buffer into the string array
i++;
}
for(i = 0; i < 2; i++)
{
printf("%s\n", stringarray[i]);
}
return 0;
}
If you didn't want to use buffer you could just writte :
while( i < 2 && fgets(stringarray[i], 5, stdin) != NULL)
{
i++;
}
Note that you get 5 characters, the last one will be the NUL terminator \0. And because you have to press enter to validate, the one before \0 will be Line Feed\n. And you will only have 3 characters you really wanted.
You can do it using dynamic allocation technique as below .
#include<stdio.h>
#include<malloc.h>
#include <stdlib.h>
int main()
{
int num;
int len=0;
int i;
printf("Enter the number of elements to be entered ");
scanf("%d",&num);
//Allocate memory for the array of strings
char **var=(char **)malloc(num * sizeof(char *));
for(i=0;i<num;i++)
{
printf("Enter the string : ");
//get strings using getline
getline(&var[i],&len,stdin);
}
for(i=0;i<num;i++)
{
printf("String %d : %s \n",i,var[i]);
}
free(var);
}