I have the task to make a little program with pointers and I am facing a problem with const char*s. The program is meant to count the number of times that a sub-string appears in a main-string. Also, the different positions, where the sub-strings start, should be saved in a char** ptr. This is my little testing code:
#include <stdio.h>
#include <string.h>
main()
{
int i=-1;
int k=0;
char** ptr;
char* str="cucumber";
char* substr="cu";
while(strstr(str, substr)!=NULL)
{
i++;
ptr[i]=strstr(str, substr);
str = strpbrk(str, substr)+1;
k++;
}
printf("%i",k);
}
It should print 2, since the sub-string 'cu' appears 2 times in 'cucumber' - yet, my compiler tells me that I am using chars, when I should use constant ones. Except, I don't know how to do that.
The strstr() function requires them. What should I change?
// note:
// 1) correction to declaration of main()
// 2) addition of return statement
// 3) 'substr' is a poor name choice for a variable, as
// a) it looks like a C lib function (it is a ACL library function)
// b) it does not clearly convey what the variable contains
// 4) clutter in the 'while' loop removed
// 5) 'while' loop is replaced by a 'for' loop so more can be accomplished with less code
// 6) unneeded variables are eliminated
// 7) the 'for' loop stops when there is no possibility of further testStr occurrences
// 8) the printf() clearly indicates what is being printed
#include <stdio.h>
#include <string.h>
int main()
{
char* testStr="cucumber";
char* findStr="cu";
int k = 0;
for( int i=0; strlen(&testStr[i]) >= strlen(findStr); i++)
{
if( strstr(&testStr[i], findStr) != NULL)
{
k++;
}
}
printf("\nnumber of occurrences of %s in %s is %d\n", findStr, testStr, k);
return(0);
}
Allocate memory for storing the pointer values
#include <stdio.h>
#include <string.h>
#define MAX_SUB_STR 10
int main()
{
int i;
int k;
char* ptr[MAX_SUB_STR];
char* str="cucumber";
char* temp;
char* substr="cu";
i = 0;
k = 0;
temp = str;
while(strstr(temp, substr)!=NULL && k < MAX_SUB_STR)
{
ptr[k]=strstr(temp, substr);
temp = ptr[k] + strlen(substr);
k++;
}
printf("%i\n",k);
for (i = 0; i < k; i++)
printf("%p\n",ptr[i]);
return 0;
}
Related
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void initRandom() {
srand(time(NULL));
}
int intUniformRnd(int a, int b){
return a + rand() % (b-a+1);
}
const char* animaisQuatro[] = {"gato", "urso","vaca"};
int main() {
char quatro[4] = {'*' , '*' , '*', '*'};
initRandom();
printf("%s\n", animaisQuatro[intUniformRnd(0,2)]);
for(int i=0;i<4;i++){
printf("%c", quatro[i]);
}
return 0;
}
I have this code that give me a random animal from the array const char* animaisQuatro[] = {"gato", "urso","vaca","lapa"}; from here
initRandom();
printf("%s\n", animaisQuatro[intUniformRnd(0,2)]);
and then I want to put that random animal in another array letter by letter but I don't know how
First I reduced your code to a minimal and reproducible example (something you should do whenever you ask a question):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void initRandom() {
srand(time(NULL));
}
int intUniformRnd(int a, int b){
return a + rand() % (b-a+1);
}
const char* animaisQuatro[] = {"gato", "urso","vaca"};
int main() {
char quatro[4] = {'*' , '*' , '*', '*'};
initRandom();
printf("%s\n", animaisQuatro[intUniformRnd(0,2)]);
for(int i=0;i<4;i++){
printf("%c", quatro[i]);
}
return 0;
}
Then you can proceed like this:
int main() {
char quatro[4] = {'*' , '*' , '*', '*'};
initRandom();
// Get the animal name from a random position
char* name = animaisQuatro[intUniformRnd(0, 2)];
// Iterate four times
for (int i = 0; i < 4; i++) {
// Assign each `name` index to its respective `quatro` position
quatro[i] = name[i];
}
printf("%s", quatro);
return 0;
}
Tip: you can avoiding hardcoding the 2 when calling intUniformRnd. Note that
printf("%d\n", (int) sizeof(animaisQuatro));
printf("%d\n", (int) sizeof(char*));
printf("%d\n", (int) sizeof(animaisQuatro) / sizeof(char*));
outputs
24
8
3
Therefore, you can do
int length = (int) sizeof(animaisQuatro) / sizeof(char*);
int pos = intUniformRnd(0, length - 1);
This way, if you want to add more elements to animaisQuatro, you don't need to change the value inside intUniformRnd.
I want to put that random animal in other array letter by letter
To copy a string to another character array, code could use
// Risky
strcpy(quatro, animaisQuatro[intUniformRnd(0,2)]);
That would overflow quatro[] if it is too small and leads to undefined behavior. (Bad)
A better way to copy and prevent buffer overflow and alert of a failure:
int len = snprintf(quatro, sizeof quatro, "%s", animaisQuatro[intUniformRnd(0,2)]);
if (len >= sizeof quatro) {
fprintf(stderr, "quatro too small.\n");
}
Since C99 and selectively afterword, code could use a variable length array to form a right-size quatro array.
const char *animal = animaisQuatro[intUniformRnd(0,2)];
size_t sz = strlen(animal) + 1;
char quatro[sz];
strcpy(quatro, animal);
Yet since intUniformRnd[] is constant, no need to copy the text, just copy the address to a pointer:
const char *quatro = animaisQuatro[intUniformRnd(0,2)];
I am working to learn C using Kochan's Programming in C 4th edition. problem 9.7 the goal is to insert a string of characters into another array. I am supposed to write a function to accomplish this. I have two problems.
When I have the algorithm print the result as it goes through the if statements, it produces the desired output, however when I change it to an %s, I only get a partial output. My hunch is that a null character is being placed where i do not want it, but I simply cannot see it.
To see what was happening, I added a printf that would track the letter and the array space it was occupying. I was surprised to see that the first letter was not 0, but was blank, and the next letter was assigned the 0. Any insight into this would be appreciated.
The funtion of interest is "insertString".
#include <stdio.h>
#include <stdbool.h>
char x[] = {"the wrong son was shot that day"};
char text[] = {"per"};
int countString (char x[])
{
int counter, z;
for (counter = 0; x[counter] != '\0'; ++counter)
z = counter+1;
return z;
}
void insertString (char text[],char x[],int n) //source, text to input, where
{
int count, clock, i = countString(text), q = countString(x);
int counter = 0;
char y[i + q];
for(count = 0; x[count] != '\0'; ++count){
if (count < n){
y[count] = x[count];
printf("%c %i", y[count], count); //The integer call is just to put a number next to the
//letter. This is where my second issue is shown.
}
else if (counter <= i){
y[count] = text[counter];
++counter;
printf("%c", y[count]);
}
else{
y[count]= x[count - counter];
printf("%c", y[count]);
}
}
printf("\n\n");
y[count-counter] = '\0';
printf("%s", y);
}
int main (void)
{
void insertString(char text[], char x[], int i);
int countString(char x[]);
int i;
insertString(text, x, 10);
return 0;
}
10 out of 10 times I post here it is because im doing something dumb, so I use SO as an absolute last resort if i am getting into the territory of just randomly trying stuff with no methodology. Thanks for your patience in advance.
Your condition is wrong in the for. It should be x[count - counter] != '\0'
In the second condition use just < to avoid overindexing. (else if (counter < i))
You put the terminating NULL char at wrong place. You should do this: y[count] = '\0'
printf inside a string routine like this is fine for debugging, but it's a poor way to write a general-purpose function because it makes it impossible to use its output for further programmatic manipulation. It can also make it difficult to reason about how the state of the function interacts in unpredictable ways with the state of the printed data.
I assume you haven't learned about dynamic memory allocation which is a prerequisite to returning strings from functions. You can inline the function logic into main or printf only at the end of the function in the meantime.
Adding to this point, a void function would need to reallocate space in the string to insert into and would be in-place. This seems likely less generally useful than allocating a new string to hold the result.
Using global variables like char x[] when there's no need is poor practice. It's better to put those strings scoped to main. Since your function can access these variables in addition to its parameters, confusion can ensue when scope and encapsulation is breached.
Use consistent formatting and avoid variable names like q that mean virtually nothing. Instead of adding comments to explain poor var names:
void insertString (char text[],char x[],int n) //source, text to input, where
You can simply name the variables exactly what they represent:
void insertString(char *dest, char *source, int add_index)
Also, now that you've mastered countString, you can abstract this by calling the builtin strlen.
Be sure to allocate enough space in buffers: char y[i + q]; should be y[i+q+1] to allow room for the null terminator '\0'.
As for the logic, I think it's easier to break into three loops without conditions instead of one loop with conditions. This makes it easier to break the problem down into the three constituent steps:
Add everything up until add_index from the dest string to the result.
Add everything in the source string to the result.
Add everything after add_index from the dest string to the result.
Using this approach, all that's left is figuring out how to map the indexes appropriately. Here it is in code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *insert_string(char *dest, char *source, int add_index) {
int source_len = strlen(source);
int dest_len = strlen(dest);
int result_size = source_len + dest_len + 1;
char *result = malloc(result_size);
for (int i = 0; i < add_index; i++) {
result[i] = dest[i];
}
for (int i = 0; i < source_len; i++) {
result[i+add_index] = source[i];
}
for (int i = add_index; i < dest_len; i++) {
result[i+add_index] = dest[i];
}
result[result_size-1] = '\0';
return result;
}
int main(void) {
char *result = insert_string("hello world", "cruel ", 6);
printf("%s\n", result);
free(result);
return 0;
}
Although this is likely for instructional purposes, these operations can be abstracted further using builtin string functions like strncpy and sprintf.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *insert_string(char *dest, char *source, int add_index) {
int result_size = strlen(dest) + strlen(source) + 1;
char *result = malloc(result_size);
char pre[add_index+1];
pre[add_index] = '\0';
strncpy(pre, dest, add_index);
sprintf(result, "%s%s%s", pre, source, dest + add_index);
return result;
}
int main(void) {
char *result = insert_string("hello world", "cruel ", 6);
printf("%s\n", result);
free(result);
return 0;
}
Doing this in-place is more straightforward. Since the result already has the prefix, you can copy the destination postfix to create a source-sized gap in the middle and then overwrite the gap using the source string. It's up to the caller to make sure that the destination buffer is large enough to hold the insertion.
#include <stdio.h>
#include <string.h>
void insert_string(char *dest, char *source, int add_index) {
int source_len = strlen(source);
int dest_len = strlen(dest);
for (int i = add_index; i < dest_len; i++) {
dest[i+add_index] = dest[i];
}
for (int i = 0; i < source_len; i++) {
dest[i+add_index] = source[i];
}
}
int main(void) {
// allocate extra space in the string to hold the insertion
char greeting[32] = "hello world";
insert_string(greeting, "cruel ", 6);
printf("%s\n", greeting);
return 0;
}
A note of caution: none of these functions handle errors at all, so they're unsafe. Correct functions should check that the add_index falls within the bounds of the dest string. This is an exercise for the reader.
The original exercise is here:
Your function is not doing it. You need to insert the string into another string not to create a new one with both mixed. You can do it this way of course and then copy it into the original one - but it is the most uneficient way to archive it (memory & timewise).
Use the correct types.
size_t mystrlen(const char *str)
{
const char *end = str;
while(*end++);
return end - str - 1;
}
char *strinsert(char *dest, size_t pos, const char *istr)
{
char *temp = dest, *work;
size_t ilen = mystrlen(istr);
size_t nmove;
while(*temp) temp++;
nmove = temp - dest - pos + 1;
work = temp;
temp += ilen;
while(nmove--) *temp-- = *work--;
work = dest + pos;
while(*istr) *work++ = *istr++;
return dest;
}
int main()
{
char dest[128] = "0123456789012345678901234567890123456789";
printf("%s", strinsert(dest, 7, "ABCD"));
}
https://godbolt.org/z/KMnLU2
I'm learning about arrays in C and I can't figure out why the following is not correct?
#include <cs50.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
string plaintext = get_string();
int x = 5;
long long N = strlen(plaintext);
string a = plaintext;
long long c = 0;
int z = x;
for(int i = 0; i < N + (N/x) ; i++)
{
if( i == x)
{
a[c] = 32;
c++;
z = (z + x);
//printf("%c\n", a[c]);
}
a[c] = plaintext[i];
//printf("%c\n", a[c]);
c++;
}
printf("%s\n", a);
}
It's meant to insert spaces into a string of text after every x chars... I know it's not efficient (I reckon I need something called pointers) but why isn't it working? I went through it using a debugger and it seems like my original string is changing as I go... but why?
Assuming string is char * then text and a point to the same string. That explains why your original string changes. What you can do is:
string a= malloc(N+1 + N/x +1);
This allocates space for a new string, into which you copy the original with a space after every x characters. Add 1 for the terminating null character and 1 "to be safe" when x or N are odd.
#include <bits/stdc++.h>
using namespace std;
#define freinput "input.txt","r",stdin
#define freoutput "output.txt","w",stdout
#define mp make_pair
#define fi first
#define sc second
#define ellapse printf("Time : %0.3lf\n",clock()*1.0/CLOCKS_PER_SEC);
typedef long long ll;
typedef unsigned long int uld;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
string s;
string stringInsertion(int x,string neww){
for(int i = 0;i<s.size();i++){
if(i!=0 && i%x==0){
neww=neww+' '+s[i];
}
else neww+=s[i];
}
return neww;
}
int main(){
cin>>s;
int x = 2;
string neww="";
cout<<stringInsertion(x,neww);
}
just set the x number.hope this help
Okay, let's do something similar first: Print out the string with spaces. Use i to loop through the string. Every time i is evenly divisibly by x, we print a space before we print the character, but not at the beginning:
void print_spaced(const char *s, int x)
{
int i;
for (i = 0; s[i]; i++) {
if (i && i % x == 0) putchar(' ');
putchar(s[i]);
}
putchar('\n');
}
You don't need to determine the length beforehand, because you can stop when you hit the terminating null character. That is, keep going as long as s[i] is not null. (Recall that s[i] is the same as s[i] != '\0' and similarly, i is the same as i != 0.)
Now let's fill a char array with the spaced out string instead of printing it:
int space_out_unsafe(char *res, const char *s, int x)
{
int i, k = 0;
for (i = 0; s[i]; i++) {
if (i && i % x == 0) res[k++] = ' ';
res[k++] = s[i];
}
res[k] = '\0';
return k;
}
This function takes an additional parameter: A char buffer to fill. It has a second index, k, which is the current length of the result buffer. Whenever we printed in the first version, we now append a character to the string:
res[k++] = '#';
Tis overwrites the current end and moves k on one position. We don't write a newline at the end, but we must null-terminate the result.
There is one problem, though: The buffer may overflow; note how I have labelled the function above unsafe. Arrays in C have a fixed size and won't grow automatically when something is appended. It is there fore a good idea to pass the maximum buffer size max to the function and check for overflow before appending:
int space_out(char *res, int max, const char *s, int x)
{
int i, k = 0;
for (i = 0; s[i]; i++) {
if (i && i % x == 0 && k < max - 1) res[k++] = ' ';
if (k < max - 1) res[k++] = s[i];
}
res[k] = '\0';
return k;
}
You can now use this function like this:
char res[20];
space_out(res, sizeof(res), "Doremifasola", 2);
puts(res);
There are other ways to accomplish this. You could allocate the memory dynamically, as Paul suggested. That way, you can cater for the additional space you need, but you also make the caller of the function take care of cleaning up the allocated memory with free. Dynamically allocating memory is something to look into after your first week. :)
Another possibility is to space out the string in place, that modify the contents of the original buffer. You still have to take care to provide the extra space, though. (Usually, in-place midofication is used when the result string is shorter, e.g. when filtering out characters.) You should also process your string from the and as not to overwrite data you need later with spaces. If you feel confident, that's an exercise for next week, too.
The code runs until it reaches the statement:
printf("%d", sumOccur(input));
The code:
#include <stdio.h>
#include <stdlib.h>
int sumOccur(int A[]);
int main(){
int input[6] = {1,1,1,2,2,3};
printf("%d", sumOccur(input));
return 0;
}
int sumOccur(int A[]) {
int sum, i;
while(A[i]!='\0'){
sum += A[i];
i++;
}
return sum;
}
If I have made any silly mistakes please oblige.
It's not the printf() crashing. It's sumOccur(). Your array has no \0 value in it, so your while() never terminates and you end up in a near-infinite loop and run off the end of the array.
The array is an array of numbers, not a string, so there is no reason whatsoever to think there there would be a null-terminator on the values. null terminators are for strings, not arrays of numbers.
In your function int sumOccur you have two problems-
1. sum and i are not initialized just declared. Initialize both to 0 .
2. Also while(A[i]!='\0') ain't going to work as expected as your array doesn't have that value in it.
Your code invokes undefined behaviour: you access A[6] and subsequent inexistent entries in sumOccur trying to find a final 0 in the array, but you do not put one in the definition of input in the main function.
-------- cut here if you are not interested in gory implementation details --------
The array is allocated on the stack, very near the top since it is instantiated in the main function. Reading beyond the end until you find a 0 likely tries to read beyond the end of the stack pages and causes a segmentation fault.
Note that you are dealing with an int array,which means it normally won't contain '\0' character.To iterate over the array you need to specify number of elements.Here is the correct way :
#include <stdio.h>
#include <stdlib.h>
int sumOccur(int A[],size_t number_of_elemets);
int main(){
int input[6] = {1,1,1,2,2,3};
//Get the number of elements
size_t n = sizeof(input) / sizeof(int);
printf("%d", sumOccur(input,n));
return 0;
}
int sumOccur(int A[],size_t number_of_elements) {
int sum = 0;
size_t i = 0;
while( i < number_of_elements )
{
sum += A[i];
i++;
}
return sum;
}
You are iterating while A[i] != '\0' but there is no '\0' in the array and also you never initialize sum which is unlikely the cause for a crash but it could be.
You need to pass the number of elements in the array, like this
#include <stdio.h>
#include <stdlib.h>
int sumOccur(size_t count, const int *A);
int sumOccurCHQrlieWay(const int *A, size_t count);
int main()
{
int input[] = {1, 1, 1, 2, 2, 3};
printf("%d", sumOccur(sizeof(input) / sizeof(*input), input));
return 0;
}
int sumOccur(size_t count, const int *A)
{
int sum;
sum = 0;
for (size_t i = 0 ; i < count ; ++i)
sum += A[i];
return sum;
}
int sumOccurCHQrlieWay(const int *A, size_t count)
{
return sumOccur(count, A);
}
This is my code:
#include<stdio.h>
#include<stdlib.h>
main(){
char *alf="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!##$%&.",text[64];
int i, alfl=69;
srand(time(0));
for(i=0;i<64;i++)
text[i] = *(alf+rand()%alfl);
printf("%s",text);
}
But at the printf function it print an heart at final of the string.
As others have suggested in the comments (#mbratch and #KerrekSB) you need a null terminator at the end of your string.
Modify your code as follows:
#include<stdio.h>
#include<stdlib.h>
main(){
char *alf="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!##$%&.",text[64];
int i, alfl=69;
srand(time(0));
for(i=0;i<63;i++)
text[i] = *(alf+rand()%alfl);
text[i] = '\0';
printf("%s",text);
}
And it should work, but as #Simon suggested there can be other things that could help improve your code and understanding of C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 64
int main() { // If you don't add a return type, int is assumed. Please specify it as void or int.
const char *alf="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!##$%&."; // This string cant be assigned to. Make sure that you stay "const-correct".
char text[LEN]; // Please avoid magic numbers here too by using a constant
int i, alfl = strlen(alf); // As #Simon says, it is better to not use magic constants.
srand(time(0));
for(i=0;i<LEN-1;i++)
text[i] = *(alf+rand()%alfl);
text[i] = '\0'; // make sure to null terminate your string.
printf("%s",text);
return 0; // If your return type is int, you must return from the function.
}
Several suggestions:
main should return an int:
int main(void)
{
return 0;
}
You should use strlen to determine the length of strings:
alfl = strlen(alf);
It's easier to use array notation:
for(i = 0; i < 64; i++)
text[i] = alf[rand() % alfl];
If you use text like a string, it must be '\0' terminated:
text[63] = '\0';