C++ vector of char vectors cannot be printed - c++

I have a c++ vector of char vectors: std::vector<std::vector<char>> ref
After putting chars in it (size increases, so chars are there) I cannot print it.
By calling this->ref.back().back() it correctly prints the last char. But if I do ref.at(0).at(pos) or ref[0].at(pos) or ref[0][pos]
nothing is printed.
Chars are put in as follows:
while (infile>>c)
{
if (c != '>') {
ref.back().push_back(c);
curSeqPos++;
}
else {
infile.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
ref.push_back(std::vector<char>(USHRT_MAX));
curSeq++;
curSeqPos = 0;
}
}
Any idea what I am doing wrong? I am a real newbie to C++ and probably missed a reference somewhere.
Any help is appreciated!

Giving my best to be constructive, here an example that works:
#include <string> // for stdout, putc
#include <vector>
std::vector<std::vector<char>> const slist =
{{'o','n','e'},{'t','w','o'},{'t','h','r','e','e'}};
int main() {
const int sz = slist[1].size();
for(int p=0; p<sz; p++) {
putc(slist[1][p],stdout);
}
putc('\n',stdout);
return(0);
}
This prints "two\n" to stdout. You cannot use printf("%s\n",slist[1]) on your character vector as one could possibly expect. This does not even raise a warning but prints just gibberish. Cout << slist[1] of the iostreams fails with a type cast error.
Are we getting towards where your problem is? Please direct us.

I cannot really make out a lot from your code but from this std::vector<std::vector<char>> ref, ref is a 2-D array of vectors.
Since ref is a 2-D array of vectors of char, every index of ref e.g., ref[1] will have to hold a vector of char. You'll have to do just that, that is create a separate vector of char to the indices of ref else any attempt to print content at that index will result in SIGSEGV error.
Also, you can't do ref[0][1] = 'd'; , except at ref[0] since you've already assigned a vector of char to it else you'll get SIGSEGV error.
std::vector<std::vector<char>> ref(7);
std::vector<char> ref1(7);
//try
//ref[0][0] = 'f'; SIGSEGV error cus ref[0] is empty
ref1[0] = 'r';
ref[0] = ref1;
ref[0][3] = 'g'; //valid
std::cout << ref[0][0]; // r

Related

How do I reverse a c string without the use of strlen?

I'm trying to implement a void function that takes a c string as its only parameter and reverses it and prints it. Below is my attempt at a solution however I'm not sure how to go about this problem.
void printBackwards(char forward[]) {
int i = 0;
char backwards[];
while (forward[i] != '\0') {
backwards[i] = forward[-i - 1];
i++;
}
cout << backwards;
}
Under such a condition, I guess you are expected to use recursion.
void printBackwards(char forward[]) {
if (!forward[0])
return;
printBackwards(forward + 1);
cout << forward[0];
}
Not being able to use strlen, we'll calculate it ourselves using a simple for loop. Then dynamically allocate a suitable buffer (add one character for the null terminating char, and I "cheated" by using calloc to zero the memory so I don't have to remember to set the null terminator. Then anoher simple loop to copy the original into the result in reverse.
#include <stdlib.h>
#include <stdio.h>
char *rev(char *s) {
size_t i;
char *s2 = s; // A pointer to the beginning as our first loop modifies s
for (i = 0; *s; s++, i++);
char *result = calloc(0, i + 1);
if (!result) return NULL; // In case calloc didn't allocate the requested memory.
for (size_t j = 0; j < i; j++)
result[j] = s2[i - j - 1];
return result;
}
Assuming you want to reverse the string rather than just printing it in reverse order, you first need to find the last character location (actually the position of the null terminator). Pseudo-code below (since this is an educational assignment):
define null_addr(pointer):
while character at pointer is not null terminator:
increment pointer
return pointer
Then you can use that inside a loop where you swap the two characters and move the pointers toward the center of the string. As soon as the pointers become equal or pass each other the string is reversed:
define reverse(left_pointer):
set right_pointer to null_addr(left_pointer)
while right_pointer > left_pointer plus one:
decrement right_pointer
swap character at left_pointer with character at right_pointer
increment left_pointer
Alternatively (and this appears to be the case since your attempt doesn't actually reverse the original string), if you need to print the string in reverse order without modifying it, you still find the last character. Then you run backwards through the string printing each character until you reach the first. That can be done with something like:
define print_reverse(pointer):
set right_pointer to null_addr(pointer)
while right_pointer > pointer:
decrement right_pointer
print character at right_pointer
That's probably better than creating a new string to hold the reverse of the original, and then printing that reverse.
One thing you should keep in mind. This very much appears to be a C-centric question, not a C++ one (it's using C strings rather than C++ strings, and uses C header files). If that's the case, you should probably avoid things like cout.
By using abstractions, like , your code will be much better at communication WHAT it is doing instead of HOW it is doing it.
#include <iostream>
#include <string>
#include <ranges>
int main()
{
std::string hello{ "!dlrow olleH" };
for (const char c : hello | std::views::reverse)
{
std::cout << c;
}
return 0;
}
Use a template
#include <iostream>
template<int N, int I=2>
void printBackwards(char (&forward)[N]) {
std::cout << forward[N-I];
if constexpr (I<N) printBackwards<N, I+1>(forward);
}
int main() {
char test[] = "elephant";
printBackwards(test);
}
While there seems to be several working answers, I thought I'd throw my hat in the stack (pun intended) since none of them take advantage of a FILO data structure (except #273K's answer, which uses a stack implicitly instead of explicitly).
What I would do is simply push everything onto a stack and then print the stack:
#include <stack>
#include <iostream>
void printBackwards(char forward[]) {
// Create a stack to hold our reversed string
std::stack<char> stk;
// Iterate through the string until we hit the null terminator
int i = 0;
while (forward[i] != '\0'){
stk.push(forward[i]);
++i;
}
// Iterate through the stack and print each character as we pop() it
while (stk.size() > 0){
std::cout << stk.top();
stk.pop();
}
// Don't forget the newline (assuming output lines should be separated)
std::cout << '\n';
}
int main(int argc, char* argv[]){
char s[] = "This is a string";
printBackwards(s);
return 0;
}
Hi guys as promised I have come back to add my own answer. This is my own way using array subscripts and using what I currently know.
#include <iostream>
using namespace std;
void printBackwards(char[]);
int main()
{
char word[] = "apples";
printBackwards(word);
return 0;
}
void printBackwards(char word[]) {
char* temp = word;
int count = 0;
while (*temp++ != '\0') {
count++;
}
for (int i = count - 1; i >= 0; i--) {
cout << word[i];
}
}
You can make a fixed-size buffer and create new ones if needed. Fill it reverse by moving the string offset back with every inserted character. Chars exceeding the buffer are returned to be processed later, so you can make a list of such buffers:
template<int SIZE>
struct ReversedCStr
{
static_assert(SIZE > 10); // just some minimal size treshold
// constexpr
ReversedCStr(char const* c_str, char const** tail = nullptr) noexcept
{
for(buffer[offset] = '\0'; *c_str != '\0';)
{
buffer[--offset] = *c_str++;
if(offset == 0) break;
}
if(tail) *tail = c_str;
}
//constexpr
char const* c_str() const noexcept { return buffer.data()+offset;};
private:
size_t offset = SIZE -1;
std::array<char,SIZE> buffer;
};
The tag is 'C++' so I assume you use C++ not C. The following code is C++11 so it should fit in every modern project. I posted the working example on godbolt.org.
It doesn't allocate memory, and is completely exception-free. The maximum memory wasted is {buffer_size + sizeof(char*)*number_of_chunks}, and can be easily turned into a list of reversed chunks like this:
char const* tail;
std::vector<ReversedCStr<11>> vec;
for(vec.emplace_back(str,&tail); *tail != '\0';)
vec.emplace_back(tail,&tail);

Why doesn't return NULL break a function? [duplicate]

This question already has answers here:
What is the behavior of printing NULL with printf's %s specifier?
(4 answers)
Closed 3 years ago.
So, my task is to make and return a copy of a given string, and in case it has failed (for example, hit enter) to return NULL. However, when I hit Enter, the program continues to work and to print out some garbage values. The fun fact though, is that the program works just fine when I run it through the Debugger (which chalenges me the most). I don't find a simple explanation for what might've gone wrong. Or is it the problem with my compiler?
#include <stdio.h>
#include <stdlib.h>
// listing functions
char *ft_strdup(char *src);
int main(void)
{
// input of a string
char c[200];
scanf("%[^\n]%*c", c);
// calling a function
char *f = ft_strdup(c);
printf("\n%s\n", f);
free(f);
return 0;
}
char *ft_strdup(char *src)
{
int i = 0;
// itearting to get the 'length' of string src
while (src[i] != '\0')
++i;
// if user has inputted nothing - return NULL and break the function
if (i == 0)
{
return NULL;
}
// otherwise, make a copy of the string
char *x = malloc(i+1);
int j = 0;
while (j != i)
{
x[j] = src[j];
++j;
}
x[i+1] = '\0';
// print out and return
printf("%s\n%s\n%i", x, src, i);
return x;
}
It prints garbage value because char c[200]; is not initialized that mean It has garbage value inside.
char c[200] = {0};
try this and probably get some crash due to NULL pointer access.
add this to avoid crash
if (f != NULL) {
printf("\n%s\n", f);
free(f);
}
The program has undefined behavior by two reasons.
The first one is that the array cwas not initialized
char c[200];
So it has indeterminate values and if the user just press the Enter key the array will not be changed.
You could initialize it in C++ like
char c[200] = {};
or in C like
char c[200] = { '\0' };
or just like
char c[200] = "";
;
The second one is you access memory beyond the the allocated array in the function ft_strdup.
x[i+1] = '\0';
you have to write
x[j] = '\0';
And you have to check the return value of the function.
Pay attention to that in C++ you should use the operators new and delete instead of the C functions malloc and free. And instead of dynamically created character arrays to store strings you should use the standard C++ class std::string.

Struggling with the fundamentals. Especially char[], char* and reading from arrays. Perhaps I should use type string

I need a bit of guidance.
I want to sharpen my skill, so I'm practicing with smaller projects.
The current challenge is to create a function that can count syllables in a user inputted word.
My thinking is to declare an array of vowels: a, e, i, o, u.
then iterate through the user inputted word, checking if any letters of the word match with the vowel array, and if yes, check if the next letter doesn't. (I'm assuming a syllable is defined by the presence of a vowel AND consonant.)
This will need nested for loops, one to iterate through the word, and then another to iterate through the vowel array with the current index of 'word'.
I haven't even figured out how I'm going to do the same for word[i+1] yet.
But I'm struggling because I can't get my program to compile due to basic errors. I should probably use a string class, but I don't know.
Here's what I've got (And it won't compile!):
#include <iostream>
char vowels[] = {'a', 'e', 'i', 'o', 'u'};
int numberOfSyllables(char *word)
{
int numberOfVowelsFound = 0;
for ( &element : word )
{
bool vowelMatch = 0;
for ( &vowel : vowels)
{
if (element == vowel)
{
vowelMatch = 1;
break;
}
}
if ((vowelMatch == 1) numberOfVowelsFound++;
}
return numberOfVowelsFound;
}
int main()
{
char *userInput[50];
std::cout << "Enter a word: ";
std::cin >> *userInput;
std::cout << numberOfSyllables(userInput) << " syllables found";
return 0;
}
This is not a code review website, but I will try my best anyway:
Your for loops don't have types:
for (TYPE &element : word )
The type you want to loop over in this case is char.
if you wanted the compiler to figure out the type for you:
for (auto &element : word)
You are looping over word with a "foreach" style loop, but a char * cannot be looped over this way. To be precise, there is no std::begin and std::end functions defined for char *, so the "foreach" style loop doesn't know where you want your string to begin/end. Either use a different style of loop, or use a type that does support "foreach" style loops (such as std::string or C++17's std::string_view).
You added an extra parenthesis ( in the if statement:
// |
// v
if ((vowelMatch == 1) numberOfVowelsFound++;
You declare your userInput variable as an "array of 40 pointers to characters", but you probably want to write "characters" to it, not "pointers to characters". Change it's type to "array of 40 characters".
Similarly, you dereference your userInput variable (probably to avoid a warning), which, because userInput is an "array of 40 (pointers to char)", will return the first, uninitialized, "pointer to char" in that array (*var is the same as var[0] in this case). Just remove the dereference operator * and change the type of the array as suggested above, and std::cin will figure out what to do. Because you (wrongfully) dereferenced userInput already to avoid a warning, std::cin thinks you want to write to the location pointed to by the uninitialized pointer. You have no control over where your program will write too at this point; it might simply crash.
Finally, you once again pass the wrong type into numberOfSyllables(userInput), as mentioned before, userInput is an "array of 40 pointers to char", while your function expects a "pointer of chars". Change the type of userInput to "array of chars", which the compiler can then convert to "pointer of chars".
Final code:
// compile with -std=c++17 for std::string_view, or use another loop style
#include <string_view>
#include <iostream>
char vowels[] = {'a', 'e', 'i', 'o', 'u'};
int numberOfSyllables(char *word)
{
int numberOfVowelsFound = 0;
// `std::string_view` can be used in "foreach" style loops
// we need to use `const char`, since `std::string_view` is a "fake string" and not writable
for (const char &element : std::string_view(word))
// Another loop style (This even works in C):
// for (int i=0; word[i] != '\0'; i++) // While the current element is not NUL
// {
// const char element = word[i]; // Remember the current element
{
bool vowelMatch = 0;
for (const char &vowel : vowels) // Use const here too just for good measure
{
if (element == vowel)
{
vowelMatch = 1;
break;
}
}
if (vowelMatch == 1) numberOfVowelsFound++; // Removed a parenthesis here
}
return numberOfVowelsFound;
}
int main()
{
char userInput[50]; // Changed type of this variable
std::cout << "Enter a word: ";
std::cin >> userInput; // Removed a dereference here
std::cout << numberOfSyllables(userInput) << " syllables found";
return 0;
}

How to read a string of unknown size in C++

I'm a newbie, at both coding and English. This is my code:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int n = 1;
char *a = new char[n], c = getchar();
while ((c != EOF) || (c != '\n'))
{
a[n-1] = c;
c = getchar();
n++;
}
cout << a;
delete[] a;
return 0;
}
I'm learning about dynamic memory allocation. The problem is to input a string whose length is unknown. My idea is to read the string character by character and stop when it reaches EOF or \n. Could you please point out the error?
And another question: I was told that new selects a memory block of the specified size. So what happens if there wasn't a large enough block?
Thanks for helping!
[I know adhering to best practices and methods available is the "good"
thing to do, but the OP should know why the current code doesn't work
and the other answers here do not seem to be answering that]
First, you should use C++ string class for this.
Second, if you are wondering why your current code is not working, it is because:
The condition inside while is wrong. It says, "Execute this block if the character is not \n or it is not EOF". So even if you press enter (c is '\n'), this block will still execute because "c is not EOF", and vice-versa.
You are allocating only 1 byte worth of memory to your char*, which is clearly not enough.
This should fairly replicate what you want, but the memory allocated is static and the string has to be limited.
int main()
{
int n=1;
char *a = new char[100],c=getchar();
while(true)
{
if(c == '\n' || c == EOF){
break;
}
a[n-1]=c;
c=getchar();
n++;
}
cout << a;
delete[] a;
return 0;
}
First of all, there is no need to use char* and new char[n]. You can use std::string.
Then you have to ask yourself:
Can the string contain whitespace characters?
Can the string span multiple lines?
If it can span multiple lines, how many lines does it span?
If the answer to the first question is "No", you can use:
std::string s;
cin >> s;
If the answer to the first question is "Yes" and the answer to the second question is "No", then you can use:
std::string s;
getline(cin, s);
If the answer to the second question is "Yes", the answer gets more complicated.
Then, you need to find answers to more questions?
Is the number of lines hard coded?
If it is not hard coded, how does the program get that number from the user?
Based on the answers to those questions, your code will vary.
#include <iostream>
#include <string>
int main() {
std::string line;
// first argument is the stream from whence the line comes.
// will read to newline or EOF
std::getline(std::cin, line);
}
Considering the restrictions of your task (no std::string, no std::vector, dynamic memory allocation), I'll try to give you a modified but working version of your code.
My idea is read the string word my word and stop when it reach EOF or
\n. Could you please point out the error?
As molbdnilo pointed out, (c!=EOF) || (c!='\n') is always true, so your loop will never end.
As mah noticed, your a buffer is only 1 char long and you don't check for the overflow, besides, You forgot to add the null terminator at the end of it.
Your second question is about what happens when new can't allocate enough memory. It throws an exception which your program should catch to manage the situation, but the best thing (not the only one actually, maybe the easiest) you can do is to terminate your program.
This is an example of how to accomplish your task given the above mentioned limitations:
#include <iostream>
using namespace std;
int main()
{
const int INITIAL_SIZE = 8;
// The following block of code could rise an exception.
try
{
int n = 0;
char c;
// Allocate some memory to store the null terminated array of chars.
char *a = new char[INITIAL_SIZE];
// what happens if new fails? It throws an exception of type std::bad_alloc
// So you better catch it.
int allocated = INITIAL_SIZE;
// read a charachter from stdin. If EOF exit loop
while( cin.get(c) )
{
// If it's a newline or a carriage return stop.
if( '\n' == c || '\r' == c )
//^ Note that ^^^ putting the literals first helps avoiding common
// error like using "=" instead of "==" in conditions.
break;
// If the array is full, it's time to reallocate it.
if ( n == allocated )
{
// There are better alternatives, of course, but I don't know which library
// you are allowed to use, so I have to assume none.
// Allocate a bigger array. The growing strategy may be different.
allocated += 2 + allocated / 2;
char *b = new char[allocated];
// Copy the old one in the new one (again, you could use std::copy).
for ( int i = 0; i < n; ++i )
{
b[i] = a[i];
}
// Release the memory handled by the old one...
delete[] a;
// but keep using the same pointer. Just remember not to delete 'b'
// so that 'a' always points to allocated memory.
a = b;
}
a[n] = c;
// A new character has been succesfuly added.
++n;
}
// Now, before using a, we have to add the null terminator.
a[n] = '\0';
// Note that a doesn't contain the '\n'.
cout << a << '\n';
// Clean up.
delete[] a;
// Normal program termination.
return 0;
}
// If 'new' fails to allocate memory a std::bad_alloc exception is thrown.
catch ( const exception &e )
{
cout << "Exception caught: " << e.what() << "\nProgram terminated.\n";
return -1;
}
}

argument list for class template "std::vector" is missing

I am in need of some help with this program. I am in my first ever programming class and have run into wall trying to getting my program to work. I have included what I have written so far but still it doesn't compile. It is giving the error: argument list for class template "std::vector" is missing.
Here is the question:
When you read a long document, there is a good chance that many words occur multiple times. Instead of storing each word, it may be beneficial to only store unique words, and to represent the document as a vector of pointers to the unique words. Write a program that implements this strategy. Read a word at a time from cin. Keep a vector <char *> of words. If the new word is not present in this vector, allocate memory, copy the word into it, and append a pointer to the new memory. If the word is already present, then append a pointer to the existing word.
Below is code snippet:
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
/* Create a vector of char pointers to hold the individual words.
Create a string input to hold the next input through cin. */
int main() {
vector words;
string input;
/* Keep the while loop running using cin as the condition to read an entire document.
This will end when a document has reached its end. */
while (cin >> input) {
/* For every word read as a string, convert the word into a c-string by allocating
a new character array with the proper size and using c_str and strcpy to copy
an identical c-string into the memory heap. */
char* temp = new char[input.length() + 1];
strcpy(temp, input.c_str());
/* Next, check if the word is already in the words array. Use a boolean variable
that updates if the word is found. Compare words by using the strcmp function;
when they are equal, strcmp equals 0. */
bool already_present = false;
for (int i = 0; i < words.size(); i++) {
if (strcmp(temp, words[i]) == 0) {
already_present = true;
}
}
/* If the word is already present, delete the allocated memory.
Otherwise, push the pointer into the words vector. */
if (already_present) {
delete temp;
} else {
words.push_back(temp);
}
}
}
I hope below code snippet could be helpful:
#include <string>
#include <iostream>
#include <string.h> // String.h for strcmp()
#include <vector> // Vector Header file is added
using namespace std;
int main() {
vector <char *> words; // vector of char *
string input;
while (cin >> input) {
char *temp = new char[input.length() + 1];
strcpy(temp, input.c_str());
bool already_present = false;
for (unsigned int i = 0; i < words.size(); i++) {
if (strcmp(temp, words[i]) == 0) {
already_present = true;
}
}
if (already_present) {
delete temp;
} else {
words.push_back(temp);
}
}
/* Print the desired output */
for(unsigned int i=0; i<words.size(); i++) {
cout << words[i] << endl;
}
return 0;
}
Any doubt, comments most welcome.
EDIT: After reading your comments, I came to the conclusion that you use Microsoft Visual Stdio. See, the reason you were getting warning is that strcpy() is potentially unsafe because it can lead to buffer overflow if you try to copy a string to a buffer that is not large enough to contain it.
Consider a code snippet for a moment:
char foo[10]; /* a buffer able to hold 9 chars (plus the null) */
char bar[] = "A string longer than 9 chars";
strcpy( foo, bar ); /* compiles ok, but VERY BAD because you have a buffer overflow
and are corrupting memory. */
strcpy_s() is safer because you have to explicitly specify the size of the target buffer, so the function will not overflow:
strcpy_s( foo, 10, bar ); /* strcpy_s will not write more than 10 characters */
The limitations of this strcpy_s() is that, it is non-standard and MS specific. Therefore if you write code to use it, your code will not be portable any more.